<html>

<head>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
<meta name=Generator content="Microsoft Word 14 (filtered)">

<style>
<!--
 /* Font Definitions */
 @font-face
	{font-family:Wingdings;
	panose-1:5 0 0 0 0 0 0 0 0 0;}
@font-face
	{font-family:宋体;
	panose-1:2 1 6 0 3 1 1 1 1 1;}
@font-face
	{font-family:黑体;
	panose-1:2 1 6 9 6 1 1 1 1 1;}
@font-face
	{font-family:黑体;
	panose-1:2 1 6 9 6 1 1 1 1 1;}
@font-face
	{font-family:方正小标宋简体;}
@font-face
	{font-family:"\@黑体";
	panose-1:2 1 6 9 6 1 1 1 1 1;}
@font-face
	{font-family:"\@宋体";
	panose-1:2 1 6 0 3 1 1 1 1 1;}
@font-face
	{font-family:"\@方正小标宋简体";}
 /* Style Definitions */
 p.MsoNormal, li.MsoNormal, div.MsoNormal
	{margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
h1
	{mso-style-link:"标题 1 Char";
	margin-top:17.0pt;
	margin-right:0cm;
	margin-bottom:16.5pt;
	margin-left:7.2pt;
	text-align:center;
	text-indent:-7.2pt;
	page-break-after:avoid;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
h2
	{mso-style-link:"标题 2 Char";
	margin-top:13.0pt;
	margin-right:0cm;
	margin-bottom:13.0pt;
	margin-left:0cm;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:0cm;
	page-break-after:avoid;
	font-size:16.0pt;
	font-family:"Arial","sans-serif";
	font-weight:bold;}
h3
	{mso-style-link:"标题 3 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:0cm;
	page-break-after:avoid;
	font-size:14.0pt;
	font-family:"Arial","sans-serif";
	font-weight:bold;}
h4
	{mso-style-link:"标题 4 Char";
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:28.8pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-28.8pt;
	page-break-after:avoid;
	font-size:12.0pt;
	font-family:"Arial","sans-serif";
	font-weight:bold;}
h5
	{mso-style-link:"标题 5 Char";
	margin-top:14.0pt;
	margin-right:0cm;
	margin-bottom:14.5pt;
	margin-left:36.0pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-36.0pt;
	line-height:156%;
	page-break-after:avoid;
	font-size:14.0pt;
	font-family:宋体;
	font-weight:bold;}
h6
	{mso-style-link:"标题 6 Char";
	margin-top:12.0pt;
	margin-right:0cm;
	margin-bottom:3.2pt;
	margin-left:43.2pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-43.2pt;
	line-height:133%;
	page-break-after:avoid;
	font-size:12.0pt;
	font-family:"Arial","sans-serif";
	font-weight:bold;}
p.MsoHeading7, li.MsoHeading7, div.MsoHeading7
	{mso-style-link:"标题 7 Char";
	margin-top:12.0pt;
	margin-right:0cm;
	margin-bottom:3.2pt;
	margin-left:50.4pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-50.4pt;
	line-height:133%;
	page-break-after:avoid;
	font-size:12.0pt;
	font-family:宋体;
	font-weight:bold;}
p.MsoHeading8, li.MsoHeading8, div.MsoHeading8
	{mso-style-link:"标题 8 Char";
	margin-top:12.0pt;
	margin-right:0cm;
	margin-bottom:3.2pt;
	margin-left:57.6pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-72.0pt;
	line-height:133%;
	page-break-after:avoid;
	font-size:12.0pt;
	font-family:"Arial","sans-serif";}
p.MsoHeading9, li.MsoHeading9, div.MsoHeading9
	{mso-style-link:"标题 9 Char";
	margin-top:12.0pt;
	margin-right:0cm;
	margin-bottom:3.2pt;
	margin-left:64.8pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-79.2pt;
	line-height:133%;
	page-break-after:avoid;
	font-size:10.5pt;
	font-family:"Arial","sans-serif";}
p.MsoIndex1, li.MsoIndex1, div.MsoIndex1
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:10.5pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-10.5pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoIndex2, li.MsoIndex2, div.MsoIndex2
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.0pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-10.5pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoIndex3, li.MsoIndex3, div.MsoIndex3
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:31.5pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-10.5pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoIndex4, li.MsoIndex4, div.MsoIndex4
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:42.0pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-10.5pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoIndex5, li.MsoIndex5, div.MsoIndex5
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:52.5pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-10.5pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoIndex6, li.MsoIndex6, div.MsoIndex6
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:63.0pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-10.5pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoIndex7, li.MsoIndex7, div.MsoIndex7
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:73.5pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-10.5pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoIndex8, li.MsoIndex8, div.MsoIndex8
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:84.0pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-10.5pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoIndex9, li.MsoIndex9, div.MsoIndex9
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:94.5pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-10.5pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoToc1, li.MsoToc1, div.MsoToc1
	{margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;
	font-weight:bold;}
p.MsoToc2, li.MsoToc2, div.MsoToc2
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.0pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoToc3, li.MsoToc3, div.MsoToc3
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:42.0pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoToc4, li.MsoToc4, div.MsoToc4
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:31.5pt;
	margin-bottom:.0001pt;
	font-size:9.0pt;
	font-family:宋体;}
p.MsoToc5, li.MsoToc5, div.MsoToc5
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:42.0pt;
	margin-bottom:.0001pt;
	font-size:9.0pt;
	font-family:宋体;}
p.MsoToc6, li.MsoToc6, div.MsoToc6
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:52.5pt;
	margin-bottom:.0001pt;
	font-size:9.0pt;
	font-family:宋体;}
p.MsoToc7, li.MsoToc7, div.MsoToc7
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:63.0pt;
	margin-bottom:.0001pt;
	font-size:9.0pt;
	font-family:宋体;}
p.MsoToc8, li.MsoToc8, div.MsoToc8
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:73.5pt;
	margin-bottom:.0001pt;
	font-size:9.0pt;
	font-family:宋体;}
p.MsoToc9, li.MsoToc9, div.MsoToc9
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:84.0pt;
	margin-bottom:.0001pt;
	font-size:9.0pt;
	font-family:宋体;}
p.MsoFootnoteText, li.MsoFootnoteText, div.MsoFootnoteText
	{mso-style-link:"脚注文本 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	layout-grid-mode:char;
	font-size:9.0pt;
	font-family:宋体;}
p.MsoCommentText, li.MsoCommentText, div.MsoCommentText
	{mso-style-link:"批注文字 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoHeader, li.MsoHeader, div.MsoHeader
	{mso-style-link:"页眉 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	layout-grid-mode:char;
	border:none;
	padding:0cm;
	font-size:9.0pt;
	font-family:宋体;}
p.MsoFooter, li.MsoFooter, div.MsoFooter
	{mso-style-link:"页脚 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	layout-grid-mode:char;
	font-size:9.0pt;
	font-family:宋体;}
p.MsoIndexHeading, li.MsoIndexHeading, div.MsoIndexHeading
	{mso-style-name:"索引标题\,索引类目\,索引类目1\,索引类目2";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoCaption, li.MsoCaption, div.MsoCaption
	{margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:"Arial","sans-serif";}
p.MsoTof, li.MsoTof, div.MsoTof
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:42.0pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-21.0pt;
	font-size:10.5pt;
	font-family:宋体;}
span.MsoFootnoteReference
	{vertical-align:super;}
p.MsoList, li.MsoList, div.MsoList
	{margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.0pt;
	margin-bottom:.0001pt;
	text-align:center;
	text-indent:-21.0pt;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoList2, li.MsoList2, div.MsoList2
	{margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoList4, li.MsoList4, div.MsoList4
	{margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.MsoDate, li.MsoDate, div.MsoDate
	{mso-style-link:"日期 Char";
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:5.0pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
a:link, span.MsoHyperlink
	{mso-style-name:"超链接\,超级链接";
	color:blue;
	text-decoration:underline;}
a:visited, span.MsoHyperlinkFollowed
	{color:purple;
	text-decoration:underline;}
p
	{mso-style-name:"普通\(网站\)\,普通 \(Web\)\,普通 \(Web\)1\,普通 \(Web\)2\,普通 \(Web\)3";
	margin-right:0cm;
	margin-left:0cm;
	font-size:12.0pt;
	font-family:宋体;}
pre
	{mso-style-name:"HTML 预设格式\,HTML 预先格式化\,HTML 预先格式化1\,HTML 预先格式化2\,HTML 预先格式化3";
	mso-style-link:"HTML 预设格式 Char\,HTML 预先格式化 Char\,HTML 预先格式化1 Char\,HTML 预先格式化2 Char\,HTML 预先格式化3 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	font-size:12.0pt;
	font-family:宋体;}
tt
	{font-family:黑体;}
p.MsoCommentSubject, li.MsoCommentSubject, div.MsoCommentSubject
	{mso-style-link:"批注主题 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	font-size:10.5pt;
	font-family:宋体;
	font-weight:bold;}
p.MsoAcetate, li.MsoAcetate, div.MsoAcetate
	{mso-style-link:"批注框文本 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:9.0pt;
	font-family:宋体;}
p.1, li.1, div.1
	{mso-style-name:样式1;
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.0pt;
	margin-bottom:.0001pt;
	text-align:center;
	text-indent:-21.0pt;
	font-size:10.5pt;
	font-family:宋体;}
p.a, li.a, div.a
	{mso-style-name:代码程序;
	mso-style-link:"代码程序 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	font-size:10.0pt;
	font-family:宋体;}
span.Char
	{mso-style-name:"代码程序 Char";
	mso-style-link:代码程序;
	font-family:宋体;}
p.a0, li.a0, div.a0
	{mso-style-name:图说明;
	mso-style-link:"图说明 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
span.Char0
	{mso-style-name:"图说明 Char";
	mso-style-link:图说明;
	font-family:宋体;}
p.0, li.0, div.0
	{mso-style-name:封面0;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:36.0pt;
	font-family:宋体;
	font-weight:bold;}
p.10, li.10, div.10
	{mso-style-name:封面1;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:18.0pt;
	font-family:宋体;
	font-weight:bold;}
p.11, li.11, div.11
	{mso-style-name:非标题1;
	margin-top:7.8pt;
	margin-right:0cm;
	margin-bottom:7.8pt;
	margin-left:0cm;
	text-align:center;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
p.a1, li.a1, div.a1
	{mso-style-name:文本居中;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.3CharChar, li.3CharChar, div.3CharChar
	{mso-style-name:"图中文字3 Char Char";
	mso-style-link:"图中文字3 Char Char Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	line-height:9.0pt;
	font-size:8.0pt;
	font-family:宋体;}
span.3CharCharChar
	{mso-style-name:"图中文字3 Char Char Char";
	mso-style-link:"图中文字3 Char Char";
	font-family:宋体;}
p.post, li.post, div.post
	{mso-style-name:邮件post;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:right;
	line-height:11.0pt;
	font-size:10.5pt;
	font-family:宋体;}
p.3, li.3, div.3
	{mso-style-name:图中字体3;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
span.3CharChar1CharCharChar
	{mso-style-name:"图中文字3 Char Char1 Char Char Char";
	font-family:宋体;}
span.3CharChar1CharChar
	{mso-style-name:"图中文字3 Char Char1 Char Char";
	font-family:宋体;}
p.5Char, li.5Char, div.5Char
	{mso-style-name:"图中文字5号 Char";
	mso-style-link:"图中文字5号 Char Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
span.5CharChar
	{mso-style-name:"图中文字5号 Char Char";
	mso-style-link:"图中文字5号 Char";
	font-family:宋体;}
p.5CharChar0, li.5CharChar0, div.5CharChar0
	{mso-style-name:"图中文字小5号 Char Char";
	mso-style-link:"图中文字小5号 Char Char Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:9.0pt;
	font-family:宋体;}
span.5CharCharChar
	{mso-style-name:"图中文字小5号 Char Char Char";
	mso-style-link:"图中文字小5号 Char Char";
	font-family:宋体;}
p.5Char0, li.5Char0, div.5Char0
	{mso-style-name:"图中文字小5号 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:9.0pt;
	font-family:宋体;}
p.5, li.5, div.5
	{mso-style-name:图中文字小5号;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	layout-grid-mode:char;
	font-size:9.0pt;
	font-family:宋体;}
p.2, li.2, div.2
	{mso-style-name:代码程序2;
	margin:0cm;
	margin-bottom:.0001pt;
	font-size:10.0pt;
	font-family:宋体;}
p.20, li.20, div.20
	{mso-style-name:图说明2;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.21, li.21, div.21
	{mso-style-name:文本居中2;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.3CharCharCharCharChar, li.3CharCharCharCharChar, div.3CharCharCharCharChar
	{mso-style-name:"图中文字3 Char Char Char Char Char";
	mso-style-link:"图中文字3 Char Char Char Char Char Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	line-height:9.0pt;
	font-size:8.0pt;
	font-family:宋体;}
span.3CharCharCharCharCharChar
	{mso-style-name:"图中文字3 Char Char Char Char Char Char";
	mso-style-link:"图中文字3 Char Char Char Char Char";
	font-family:宋体;}
p.a2, li.a2, div.a2
	{mso-style-name:图居中;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.110, li.110, div.110
	{mso-style-name:"样式 标题 1 + 居中1";
	margin-right:0cm;
	margin-left:0cm;
	text-align:center;
	page-break-after:avoid;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
span.1Char
	{mso-style-name:"标题 1 Char";
	mso-style-link:"标题 1";
	font-weight:bold;}
p.22, li.22, div.22
	{mso-style-name:"样式 列表 2 + 居中";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.23, li.23, div.23
	{mso-style-name:列表2;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.50, li.50, div.50
	{mso-style-name:图中文字5号;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.111, li.111, div.111
	{mso-style-name:样式11;
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.0pt;
	margin-bottom:.0001pt;
	text-align:center;
	text-indent:-21.0pt;
	font-size:10.5pt;
	font-family:宋体;}
p.12, li.12, div.12
	{mso-style-name:代码程序1;
	margin:0cm;
	margin-bottom:.0001pt;
	font-size:10.0pt;
	font-family:宋体;}
p.13, li.13, div.13
	{mso-style-name:图说明1;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.01, li.01, div.01
	{mso-style-name:封面01;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:36.0pt;
	font-family:宋体;
	font-weight:bold;}
p.112, li.112, div.112
	{mso-style-name:封面11;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:18.0pt;
	font-family:宋体;
	font-weight:bold;}
p.113, li.113, div.113
	{mso-style-name:非标题11;
	margin-top:7.8pt;
	margin-right:0cm;
	margin-bottom:7.8pt;
	margin-left:0cm;
	text-align:center;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
p.14, li.14, div.14
	{mso-style-name:文本居中1;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.3Char1, li.3Char1, div.3Char1
	{mso-style-name:"图中文字3 Char1";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	line-height:9.0pt;
	font-size:8.0pt;
	font-family:宋体;}
p.post1, li.post1, div.post1
	{mso-style-name:邮件post1;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:right;
	line-height:11.0pt;
	font-size:10.5pt;
	font-family:宋体;}
p.31, li.31, div.31
	{mso-style-name:图中字体31;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
p.5Char1, li.5Char1, div.5Char1
	{mso-style-name:"图中文字5号 Char1";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.5CharChar1, li.5CharChar1, div.5CharChar1
	{mso-style-name:"图中文字小5号 Char Char1";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:9.0pt;
	font-family:宋体;}
p.5Char10, li.5Char10, div.5Char10
	{mso-style-name:"图中文字小5号 Char1";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:9.0pt;
	font-family:宋体;}
p.51, li.51, div.51
	{mso-style-name:图中文字小5号1;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:9.0pt;
	font-family:宋体;}
p.120, li.120, div.120
	{mso-style-name:样式12;
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.0pt;
	margin-bottom:.0001pt;
	text-align:center;
	text-indent:-21.0pt;
	font-size:10.5pt;
	font-family:宋体;}
p.02, li.02, div.02
	{mso-style-name:封面02;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:36.0pt;
	font-family:宋体;
	font-weight:bold;}
p.121, li.121, div.121
	{mso-style-name:封面12;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:18.0pt;
	font-family:宋体;
	font-weight:bold;}
p.122, li.122, div.122
	{mso-style-name:非标题12;
	margin-top:7.8pt;
	margin-right:0cm;
	margin-bottom:7.8pt;
	margin-left:0cm;
	text-align:center;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
p.3Char2, li.3Char2, div.3Char2
	{mso-style-name:"图中文字3 Char2";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	line-height:9.0pt;
	font-size:8.0pt;
	font-family:宋体;}
p.post2, li.post2, div.post2
	{mso-style-name:邮件post2;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:right;
	line-height:11.0pt;
	font-size:10.5pt;
	font-family:宋体;}
p.32, li.32, div.32
	{mso-style-name:图中字体32;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
p.5Char2, li.5Char2, div.5Char2
	{mso-style-name:"图中文字小5号 Char2";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:9.0pt;
	font-family:宋体;}
p.52, li.52, div.52
	{mso-style-name:图中文字小5号2;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:9.0pt;
	font-family:宋体;}
p.3CharCharCharChar, li.3CharCharCharChar, div.3CharCharCharChar
	{mso-style-name:"图中文字3 Char Char Char Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	line-height:9.0pt;
	font-size:8.0pt;
	font-family:宋体;}
p.130, li.130, div.130
	{mso-style-name:样式13;
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.0pt;
	margin-bottom:.0001pt;
	text-align:center;
	text-indent:-21.0pt;
	font-size:10.5pt;
	font-family:宋体;}
p.30, li.30, div.30
	{mso-style-name:代码程序3;
	margin:0cm;
	margin-bottom:.0001pt;
	font-size:10.0pt;
	font-family:宋体;}
p.03, li.03, div.03
	{mso-style-name:封面03;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:36.0pt;
	font-family:宋体;
	font-weight:bold;}
p.131, li.131, div.131
	{mso-style-name:封面13;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:18.0pt;
	font-family:宋体;
	font-weight:bold;}
p.132, li.132, div.132
	{mso-style-name:非标题13;
	margin-top:7.8pt;
	margin-right:0cm;
	margin-bottom:7.8pt;
	margin-left:0cm;
	text-align:center;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
p.33, li.33, div.33
	{mso-style-name:文本居中3;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.3Char3, li.3Char3, div.3Char3
	{mso-style-name:"图中文字3 Char3";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	line-height:9.0pt;
	font-size:8.0pt;
	font-family:宋体;}
p.post3, li.post3, div.post3
	{mso-style-name:邮件post3;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:right;
	line-height:11.0pt;
	font-size:10.5pt;
	font-family:宋体;}
p.330, li.330, div.330
	{mso-style-name:图中字体33;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
p.5Char20, li.5Char20, div.5Char20
	{mso-style-name:"图中文字5号 Char2";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.5CharChar2, li.5CharChar2, div.5CharChar2
	{mso-style-name:"图中文字小5号 Char Char2";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:9.0pt;
	font-family:宋体;}
p.5Char3, li.5Char3, div.5Char3
	{mso-style-name:"图中文字小5号 Char3";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:9.0pt;
	font-family:宋体;}
p.53, li.53, div.53
	{mso-style-name:图中文字小5号3;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:9.0pt;
	font-family:宋体;}
p.3Char, li.3Char, div.3Char
	{mso-style-name:"图中文字3 Char";
	mso-style-link:"图中文字3 Char Char5";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	line-height:9.0pt;
	font-size:8.0pt;
	font-family:宋体;}
span.3CharChar5
	{mso-style-name:"图中文字3 Char Char5";
	mso-style-link:"图中文字3 Char";
	font-family:宋体;}
p.54, li.54, div.54
	{mso-style-name:图中文字小5紧密;
	margin:0cm;
	margin-bottom:.0001pt;
	line-height:9.0pt;
	text-autospace:ideograph-numeric;
	font-size:9.0pt;
	font-family:宋体;}
p.24, li.24, div.24
	{mso-style-name:居中2号粗宋体;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
p.15, li.15, div.15
	{mso-style-name:"样式 标题 1 + 居中";
	margin-top:17.0pt;
	margin-right:0cm;
	margin-bottom:16.5pt;
	margin-left:0cm;
	text-align:center;
	page-break-after:avoid;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
p.25, li.25, div.25
	{mso-style-name:"样式 标题 2 + 行距\: 单倍行距";
	margin-top:13.0pt;
	margin-right:0cm;
	margin-bottom:13.0pt;
	margin-left:28.9pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-28.9pt;
	page-break-after:avoid;
	font-size:16.0pt;
	font-family:"Arial","sans-serif";
	font-weight:bold;}
span.2Char
	{mso-style-name:"标题 2 Char";
	mso-style-link:"标题 2";
	font-family:"Arial","sans-serif";
	font-weight:bold;}
p.34, li.34, div.34
	{mso-style-name:列表3;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.35, li.35, div.35
	{mso-style-name:表3;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.4, li.4, div.4
	{mso-style-name:图说明4;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.40, li.40, div.40
	{mso-style-name:列表4;
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.0pt;
	margin-bottom:.0001pt;
	text-align:center;
	text-indent:-21.0pt;
	font-size:10.5pt;
	font-family:宋体;}
p.41, li.41, div.41
	{mso-style-name:表4;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.55, li.55, div.55
	{mso-style-name:图说明5;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.56, li.56, div.56
	{mso-style-name:列表5;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.57, li.57, div.57
	{mso-style-name:表5;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.6, li.6, div.6
	{mso-style-name:列表6;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.60, li.60, div.60
	{mso-style-name:表6;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.61, li.61, div.61
	{mso-style-name:图说明6;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.7, li.7, div.7
	{mso-style-name:列表7;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.70, li.70, div.70
	{mso-style-name:图说明7;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.71, li.71, div.71
	{mso-style-name:表7;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.8, li.8, div.8
	{mso-style-name:列表8;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.9, li.9, div.9
	{mso-style-name:列表9;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.90, li.90, div.90
	{mso-style-name:图说明9;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.100, li.100, div.100
	{mso-style-name:列表10;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.101, li.101, div.101
	{mso-style-name:图说明10;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.114, li.114, div.114
	{mso-style-name:列表11;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.115, li.115, div.115
	{mso-style-name:图说明11;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.116, li.116, div.116
	{mso-style-name:表11;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.123, li.123, div.123
	{mso-style-name:列表12;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.124, li.124, div.124
	{mso-style-name:图说明12;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.133, li.133, div.133
	{mso-style-name:图说明13;
	mso-style-link:"图说明13 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
span.13Char
	{mso-style-name:"图说明13 Char";
	mso-style-link:图说明13;
	font-family:宋体;}
p.134, li.134, div.134
	{mso-style-name:列表13;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.26, li.26, div.26
	{mso-style-name:附录2;
	margin-top:13.0pt;
	margin-right:0cm;
	margin-bottom:13.0pt;
	margin-left:0cm;
	text-align:justify;
	text-justify:inter-ideograph;
	page-break-after:avoid;
	font-size:16.0pt;
	font-family:"Arial","sans-serif";
	font-weight:bold;}
p.36, li.36, div.36
	{mso-style-name:附录3;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	page-break-after:avoid;
	font-size:14.0pt;
	font-family:"Arial","sans-serif";
	font-weight:bold;}
span.3Char0
	{mso-style-name:"标题 3 Char";
	mso-style-link:"标题 3";
	font-family:"Arial","sans-serif";
	font-weight:bold;}
p.16, li.16, div.16
	{mso-style-name:附录1;
	margin-top:17.0pt;
	margin-right:0cm;
	margin-bottom:16.5pt;
	margin-left:0cm;
	text-align:center;
	page-break-after:avoid;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
p.17, li.17, div.17
	{mso-style-name:附录表1;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.42, li.42, div.42
	{mso-style-name:附录4;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	page-break-after:avoid;
	font-size:12.0pt;
	font-family:"Arial","sans-serif";
	font-weight:bold;}
span.4Char
	{mso-style-name:"标题 4 Char";
	mso-style-link:"标题 4";
	font-family:"Arial","sans-serif";
	font-weight:bold;}
p.a3, li.a3, div.a3
	{mso-style-name:附录图说明;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.27, li.27, div.27
	{mso-style-name:序标题2;
	margin-top:13.0pt;
	margin-right:0cm;
	margin-bottom:13.0pt;
	margin-left:28.8pt;
	text-align:justify;
	text-justify:inter-ideograph;
	text-indent:-28.8pt;
	page-break-after:avoid;
	font-size:16.0pt;
	font-family:"Arial","sans-serif";
	font-weight:bold;}
p.a4, li.a4, div.a4
	{mso-style-name:参考标题;
	margin-top:7.8pt;
	margin-right:0cm;
	margin-bottom:7.8pt;
	margin-left:0cm;
	text-align:center;
	page-break-after:avoid;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
p.18, li.18, div.18
	{mso-style-name:索引标题1;
	margin-top:7.8pt;
	margin-right:0cm;
	margin-bottom:7.8pt;
	margin-left:0cm;
	text-align:center;
	page-break-after:avoid;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
p.19, li.19, div.19
	{mso-style-name:列表1;
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.25pt;
	margin-bottom:.0001pt;
	text-align:center;
	text-indent:-21.25pt;
	font-size:10.5pt;
	font-family:宋体;}
p.1a, li.1a, div.1a
	{mso-style-name:表1;
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.25pt;
	margin-bottom:.0001pt;
	text-align:center;
	text-indent:-21.25pt;
	font-size:10.5pt;
	font-family:宋体;}
p.37, li.37, div.37
	{mso-style-name:图说明3;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.62, li.62, div.62
	{mso-style-name:表中字体6号;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	layout-grid-mode:char;
	font-size:7.5pt;
	font-family:宋体;}
p.a5, li.a5, div.a5
	{mso-style-name:正文代码;
	mso-style-link:"正文代码 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
span.Char1
	{mso-style-name:"正文代码 Char";
	mso-style-link:正文代码;
	font-family:宋体;}
p.43, li.43, div.43
	{mso-style-name:"样式 标题 4 +";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	page-break-after:avoid;
	font-size:12.0pt;
	font-family:"Arial","sans-serif";
	font-weight:bold;}
p.140, li.140, div.140
	{mso-style-name:表14;
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.25pt;
	margin-bottom:.0001pt;
	text-align:center;
	text-indent:-21.25pt;
	font-size:10.5pt;
	font-family:宋体;}
p.141, li.141, div.141
	{mso-style-name:图说明14;
	mso-style-link:"图说明14 Char";
	margin-top:0cm;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:21.25pt;
	margin-bottom:.0001pt;
	text-align:center;
	text-indent:-21.25pt;
	font-size:10.5pt;
	font-family:宋体;}
span.14Char
	{mso-style-name:"图说明14 Char";
	mso-style-link:图说明14;
	font-family:宋体;}
p.a6, li.a6, div.a6
	{mso-style-name:文件目录表;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
p.a7, li.a7, div.a7
	{mso-style-name:"样式 正文 +";
	mso-style-link:"样式 正文 + Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
span.Char2
	{mso-style-name:"样式 正文 + Char";
	mso-style-link:"样式 正文 +";
	font-family:"Times New Roman","serif";}
p.a8, li.a8, div.a8
	{mso-style-name:表格题注;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.a9, li.a9, div.a9
	{mso-style-name:列表题注;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:"Arial","sans-serif";}
p.aa, li.aa, div.aa
	{mso-style-name:图题注;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:"Arial","sans-serif";}
p.ab, li.ab, div.ab
	{mso-style-name:程序题注;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:"Arial","sans-serif";}
p.ac, li.ac, div.ac
	{mso-style-name:框中文字;
	margin-top:0cm;
	margin-right:21.0pt;
	margin-bottom:0cm;
	margin-left:21.0pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	border:none;
	padding:0cm;
	font-size:9.0pt;
	font-family:宋体;}
p.125, li.125, div.125
	{mso-style-name:"样式 标题 1 + 居中2";
	margin-top:17.0pt;
	margin-right:0cm;
	margin-bottom:16.5pt;
	margin-left:0cm;
	text-align:center;
	page-break-after:avoid;
	font-size:22.0pt;
	font-family:宋体;
	font-weight:bold;}
p.ad, li.ad, div.ad
	{mso-style-name:"样式 题注 + 宋体 五号 居中";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:黑体;}
p.1b, li.1b, div.1b
	{mso-style-name:序标题1;
	margin-top:17.0pt;
	margin-right:0cm;
	margin-bottom:16.5pt;
	margin-left:0cm;
	line-height:240%;
	page-break-after:avoid;
	font-size:16.0pt;
	font-family:宋体;
	font-weight:bold;}
p.38, li.38, div.38
	{mso-style-name:序标题3;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	page-break-after:avoid;
	font-size:12.0pt;
	font-family:方正小标宋简体;}
p.63, li.63, div.63
	{mso-style-name:表中文字6号;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:7.5pt;
	font-family:宋体;}
p.64, li.64, div.64
	{mso-style-name:图中文字6号左对齐;
	margin:0cm;
	margin-bottom:.0001pt;
	line-height:10.0pt;
	layout-grid-mode:char;
	font-size:7.5pt;
	font-family:宋体;}
p.65, li.65, div.65
	{mso-style-name:图中文字6号;
	mso-style-link:"图中文字6号 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	line-height:10.0pt;
	layout-grid-mode:char;
	font-size:7.5pt;
	font-family:宋体;}
span.6Char
	{mso-style-name:"图中文字6号 Char";
	mso-style-link:图中文字6号;
	font-family:宋体;}
p.ae, li.ae, div.ae
	{mso-style-name:图标;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
p.28, li.28, div.28
	{mso-style-name:图标2;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
p.af, li.af, div.af
	{mso-style-name:习题标题;
	margin-top:6.0pt;
	margin-right:0cm;
	margin-bottom:0cm;
	margin-left:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	page-break-after:avoid;
	font-size:14.0pt;
	font-family:黑体;}
p.1c, li.1c, div.1c
	{mso-style-name:部分编号1;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:16.0pt;
	font-family:宋体;}
p.af0, li.af0, div.af0
	{mso-style-name:表标题;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:"Arial","sans-serif";}
p.af1, li.af1, div.af1
	{mso-style-name:"样式 题注 + 居中";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:宋体;}
p.ListTitle, li.ListTitle, div.ListTitle
	{mso-style-name:ListTitle;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:"Arial","sans-serif";}
p.FigureTitle, li.FigureTitle, div.FigureTitle
	{mso-style-name:FigureTitle;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:"Arial","sans-serif";}
p.TableTitle, li.TableTitle, div.TableTitle
	{mso-style-name:TableTitle;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:"Arial","sans-serif";}
p.ProgramTitle, li.ProgramTitle, div.ProgramTitle
	{mso-style-name:ProgramTitle;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:center;
	font-size:10.5pt;
	font-family:"Arial","sans-serif";}
p.RightText, li.RightText, div.RightText
	{mso-style-name:RightText;
	margin-top:0cm;
	margin-right:21.0pt;
	margin-bottom:0cm;
	margin-left:42.0pt;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	border:none;
	padding:0cm;
	font-size:9.0pt;
	font-family:宋体;}
p.af2, li.af2, div.af2
	{mso-style-name:表中文字小五;
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:9.0pt;
	font-family:宋体;}
p.af3, li.af3, div.af3
	{mso-style-name:关键词;
	mso-style-link:"关键词 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
span.Char3
	{mso-style-name:"关键词 Char";
	mso-style-link:关键词;
	font-family:宋体;}
p.af4, li.af4, div.af4
	{mso-style-name:文件名;
	mso-style-link:"文件名 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
span.Char4
	{mso-style-name:"文件名 Char";
	mso-style-link:文件名;
	font-family:宋体;}
p.af5, li.af5, div.af5
	{mso-style-name:选项;
	mso-style-link:"选项 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
span.Char5
	{mso-style-name:"选项 Char";
	mso-style-link:选项;
	font-family:宋体;}
p.af6, li.af6, div.af6
	{mso-style-name:命令行;
	mso-style-link:"命令行 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
span.Char6
	{mso-style-name:"命令行 Char";
	mso-style-link:命令行;
	font-family:宋体;}
p.af7, li.af7, div.af7
	{mso-style-name:函数名;
	mso-style-link:"函数名 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
span.Char7
	{mso-style-name:"函数名 Char";
	mso-style-link:函数名;
	font-family:宋体;}
p.af8, li.af8, div.af8
	{mso-style-name:寄存器名;
	mso-style-link:"寄存器名 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
span.Char8
	{mso-style-name:"寄存器名 Char";
	mso-style-link:寄存器名;
	font-family:"Times New Roman","serif";}
p.af9, li.af9, div.af9
	{mso-style-name:变量名;
	mso-style-link:"变量名 Char";
	margin:0cm;
	margin-bottom:.0001pt;
	text-align:justify;
	text-justify:inter-ideograph;
	font-size:10.5pt;
	font-family:宋体;}
span.Char9
	{mso-style-name:"变量名 Char";
	mso-style-link:变量名;
	font-family:宋体;}
p.58, li.58, div.58
	{mso-style-name:图中文字小5号左;
	margin:0cm;
	margin-bottom:.0001pt;
	font-size:9.0pt;
	font-family:宋体;}
p.59, li.59, div.59
	{mso-style-name:图中文字小5号靠左;
	margin:0cm;
	margin-bottom:.0001pt;
	layout-grid-mode:char;
	font-size:9.0pt;
	font-family:宋体;}
p.926, li.926, div.926
	{mso-style-name:"样式 代码程序 + 左侧\:  9\.26 厘米";
	margin:0cm;
	margin-bottom:.0001pt;
	layout-grid-mode:char;
	font-size:10.0pt;
	font-family:宋体;}
span.5Char4
	{mso-style-name:"标题 5 Char";
	mso-style-link:"标题 5";
	font-weight:bold;}
span.6Char0
	{mso-style-name:"标题 6 Char";
	mso-style-link:"标题 6";
	font-family:"Arial","sans-serif";
	font-weight:bold;}
span.7Char
	{mso-style-name:"标题 7 Char";
	mso-style-link:"标题 7";
	font-weight:bold;}
span.8Char
	{mso-style-name:"标题 8 Char";
	mso-style-link:"标题 8";
	font-family:"Arial","sans-serif";}
span.9Char
	{mso-style-name:"标题 9 Char";
	mso-style-link:"标题 9";
	font-family:"Arial","sans-serif";}
span.Chara
	{mso-style-name:"脚注文本 Char";
	mso-style-link:脚注文本;
	font-family:宋体;}
span.Charb
	{mso-style-name:"批注文字 Char";
	mso-style-link:批注文字;
	font-family:宋体;}
span.Charc
	{mso-style-name:"页眉 Char";
	mso-style-link:页眉;
	font-family:宋体;}
span.Chard
	{mso-style-name:"页脚 Char";
	mso-style-link:页脚;
	font-family:宋体;}
span.Chare
	{mso-style-name:"日期 Char";
	mso-style-link:日期;
	font-family:宋体;}
span.HTMLChar
	{mso-style-name:"HTML 预设格式 Char\,HTML 预先格式化 Char\,HTML 预先格式化1 Char\,HTML 预先格式化2 Char\,HTML 预先格式化3 Char";
	mso-style-link:"HTML 预设格式\,HTML 预先格式化\,HTML 预先格式化1\,HTML 预先格式化2\,HTML 预先格式化3";
	font-family:宋体;}
span.Charf
	{mso-style-name:"批注主题 Char";
	mso-style-link:批注主题;
	font-family:宋体;
	font-weight:bold;}
span.Charf0
	{mso-style-name:"批注框文本 Char";
	mso-style-link:批注框文本;
	font-family:宋体;}
span.3CharChar1
	{mso-style-name:"图中文字3 Char Char1";
	font-family:宋体;}
span.3CharChar3
	{mso-style-name:"图中文字3 Char Char3";
	font-family:宋体;}
span.3CharChar13
	{mso-style-name:"图中文字3 Char Char13";
	font-family:宋体;}
span.3CharChar12
	{mso-style-name:"图中文字3 Char Char12";
	font-family:宋体;}
span.3CharChar11
	{mso-style-name:"图中文字3 Char Char11";
	font-family:宋体;}
.MsoChpDefault
	{font-size:10.0pt;}
 /* Page Definitions */
 @page WordSection1
	{size:595.3pt 841.9pt;
	margin:72.0pt 54.0pt 72.0pt 54.0pt;
	layout-grid:15.6pt;}
div.WordSection1
	{page:WordSection1;}
 /* List Definitions */
 ol
	{margin-bottom:0cm;}
ul
	{margin-bottom:0cm;}
-->
</style>

</head>

<body lang=ZH-CN link=blue vlink=purple style='text-justify-trim:punctuation'>

<div class=WordSection1 style='layout-grid:15.6pt'>

<p class=ab><a name="_Toc53320618"><span style='font-family:黑体'>程序</span><span
lang=EN-US>9-2 linux/kernel/blk_drv/hd.c</span></a></p>

<div class=a align=center style='text-align:center'><span lang=EN-US>

<hr size=4 width="100%" align=center>

</span></div>

<p class=a><span lang=EN-US>&nbsp; <u><span style='color:blue'>1</span></u> <b><i>/*</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp; <u><span style='color:blue'>2</span></u> <b><i>&nbsp;*&nbsp;
linux/kernel/hd.c</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp; <u><span style='color:blue'>3</span></u> <b><i>&nbsp;*</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp; <u><span style='color:blue'>4</span></u> <b><i>&nbsp;*&nbsp;
(C) 1991&nbsp; Linus Torvalds</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp; <u><span style='color:blue'>5</span></u> <b><i>&nbsp;*/</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp; <u><span style='color:blue'>6</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp; <u><span style='color:blue'>7</span></u> <b><i>/*</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp; <u><span style='color:blue'>8</span></u> <b><i>&nbsp;*
This is the low-level hd interrupt support. It traverses the</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp; <u><span style='color:blue'>9</span></u> <b><i>&nbsp;*
request-list, using interrupts to jump between functions. As</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>10</span></u> <b><i>&nbsp;*
all the functions are called within interrupts, we may not</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>11</span></u> <b><i>&nbsp;*
sleep. Special care is recommended.</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>12</span></u> <b><i>&nbsp;*
</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>13</span></u> <b><i>&nbsp;*&nbsp;
modified by Drew Eckhardt to check nr of hd's from the CMOS.</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>14</span></u> <b><i>&nbsp;*/</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /*</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>本程序是底层硬盘中断辅助程序。主要用于扫描请求项队列，使用中断</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>在函数之间跳转。由于所有的函数都是在中断里调用的，所以这些函数</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span>不可以睡眠。请特别注意。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; * </span><i>由<span
lang=EN-US>Drew Eckhardt</span>修改，利用<span lang=EN-US>CMOS</span>信息检测硬盘数。</i></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; */</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>15</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>16</span></u>
#include &lt;linux/config.h&gt; // </span>内核配置头文件。定义键盘语言和硬盘类型（<span lang=EN-US>HD_TYPE</span>）选项。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>17</span></u>
#include &lt;linux/sched.h&gt;&nbsp; // </span>调度程序头文件，定义任务结构<span lang=EN-US>task_struct</span>、任务<span
lang=EN-US>0</span>数据等。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>18</span></u>
#include &lt;linux/fs.h&gt;&nbsp;&nbsp;&nbsp;&nbsp; // </span>文件系统头文件。定义文件表结构（<span
lang=EN-US>file</span>、<span lang=EN-US>m_inode</span>）等。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>19</span></u>
#include &lt;linux/kernel.h&gt; // </span>内核头文件。含有一些内核常用函数的原形定义。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>20</span></u>
#include &lt;linux/hdreg.h&gt;&nbsp; // </span>硬盘参数头文件。定义硬盘寄存器端口、状态码、分区表等信息。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>21</span></u>
#include &lt;asm/system.h&gt;&nbsp;&nbsp; // </span>系统头文件。定义设置或修改描述符<span
lang=EN-US>/</span>中断门等的汇编宏。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>22</span></u>
#include &lt;asm/io.h&gt;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // io</span>头文件。定义硬件端口输入<span
lang=EN-US>/</span>输出宏汇编语句。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>23</span></u>
#include &lt;asm/segment.h&gt;&nbsp; // </span>段操作头文件。定义了有关段寄存器操作的嵌入式汇编函数。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>24</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>定义硬盘主设备号符号常数。在驱动程序中，主设备号必须在包含<span
lang=EN-US>blk.h</span>文件之前被定义。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>因为<span lang=EN-US>blk.h</span>文件中要用到这个符号常数值来确定一些列其他相关符号常数和宏。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>25</span></u>
#define <u><span style='color:blue'>MAJOR_NR</span></u> 3&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>硬盘主设备号是<span lang=EN-US>3</span>。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>26</span></u>
#include &quot;<u><span style='color:blue'>blk.h</span></u>&quot;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>块设备头文件。定义请求数据结构、块设备数据结构和宏等信息。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>27</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>读<span lang=EN-US>CMOS</span>参数宏函数。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>这段宏读取<span lang=EN-US>CMOS</span>中硬盘信息。<span
lang=EN-US>outb_p</span>、<span lang=EN-US>inb_p</span>是<span lang=EN-US>include/asm/io.h</span>中定义的端口输入输出宏。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>与<span lang=EN-US>init/main.c</span>中读取<span
lang=EN-US>CMOS</span>时钟信息的宏完全一样。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>28</span></u>
#define <u><span style='color:blue'>CMOS_READ</span></u>(addr) ({ \</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>29</span></u> <u><span
style='color:blue'>outb_p</span></u>(0x80|addr,0x70); \&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// 0x70</span>是写端口号，<span lang=EN-US>0x80|addr</span>是要读的<span lang=EN-US>CMOS</span>内存地址。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>30</span></u> <u><span
style='color:blue'>inb_p</span></u>(0x71); \&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// 0x71</span>是读端口号。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>31</span></u> })</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>32</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>33</span></u> <b><i>/*
Max read/write errors/sector */</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /* </span>每扇区读<span lang=EN-US>/</span>写操作允许的最多出错次数<span
lang=EN-US> */</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>34</span></u>
#define <u><span style='color:blue'>MAX_ERRORS</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
7&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // </span>读<span
lang=EN-US>/</span>写一个扇区时允许的最多出错次数。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>35</span></u>
#define <u><span style='color:blue'>MAX_HD</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
2&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // </span>系统支持的最多硬盘数。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>36</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>重新校正处理函数。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>复位操作时在硬盘中断处理程序中调用的重新校正函数<span
lang=EN-US>(311</span>行<span lang=EN-US>)</span>。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>37</span></u>
static void <u><span style='color:blue'>recal_intr</span></u>(void);</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>读写硬盘失败处理调用函数。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>结束本次请求项处理或者设置复位标志要求执行复位硬盘控制器操作后再重试（<span
lang=EN-US>242</span>行）。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>38</span></u> static
void <u><span style='color:blue'>bad_rw_intr</span></u>(void);</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>39</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>重新校正标志。当设置了该标志，程序中会调用<span
lang=EN-US>recal_intr()</span>以将磁头移动到<span lang=EN-US>0</span>柱面。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>40</span></u>
static int <u><span style='color:blue'>recalibrate</span></u> = 0;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp; // </span>复位标志。当发生读写错误时会设置该标志并调用相关复位函数，以复位硬盘和控制器。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>41</span></u>
static int <u><span style='color:blue'>reset</span></u> = 0;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>42</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>43</span></u> <b><i>/*</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>44</span></u> <b><i>&nbsp;*&nbsp;
This struct defines the HD's and their types.</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>45</span></u> <b><i>&nbsp;*/</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /* </span>下面结构定义了硬盘参数及类型<span
lang=EN-US> */</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>硬盘信息结构（<span
lang=EN-US>Harddisk information struct</span>）。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>各字段分别是磁头数、每磁道扇区数、柱面数、写前预补偿柱面号、磁头着陆区柱面号、</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>控制字节。它们的含义请参见程序列表后的说明。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>46</span></u>
struct <u><span style='color:blue'>hd_i_struct</span></u> {</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>47</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
int <u><span style='color:blue'>head</span></u>,sect,cyl,wpcom,lzone,ctl;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>48</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
};</span></p>

<p class=a><span lang=EN-US>&nbsp;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>如果已经在<span lang=EN-US>include/linux/config.h</span>配置文件中定义了符号常数<span
lang=EN-US>HD_TYPE</span>，就取其中定义</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>好的参数作为硬盘信息数组<span
lang=EN-US>hd_info[]</span>中的数据。否则先默认都设为<span lang=EN-US>0</span>值，在<span
lang=EN-US>setup()</span>函数</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>中会重新进行设置。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>49</span></u>
#ifdef HD_TYPE</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>50</span></u>
struct <u><span style='color:blue'>hd_i_struct</span></u> <u><span
style='color:blue'>hd_info</span></u>[] = { HD_TYPE };&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>硬盘信息数组。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>51</span></u>
#define <u><span style='color:blue'>NR_HD</span></u> ((sizeof (<u><span
style='color:blue'>hd_info</span></u>))/(sizeof (struct <u><span
style='color:blue'>hd_i_struct</span></u>)))&nbsp; // </span>计算硬盘个数。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>52</span></u>
#else</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>53</span></u>
struct <u><span style='color:blue'>hd_i_struct</span></u> <u><span
style='color:blue'>hd_info</span></u>[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} };</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>54</span></u>
static int <u><span style='color:blue'>NR_HD</span></u> = 0;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>55</span></u>
#endif</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>56</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>定义硬盘分区结构。给出每个分区从硬盘<span
lang=EN-US>0</span>道开始算起的物理起始扇区号和分区扇区总数。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>其中<span lang=EN-US>5</span>的倍数处的项（例如<span
lang=EN-US>hd[0]</span>和<span lang=EN-US>hd[5]</span>等）代表整个硬盘的参数。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>57</span></u>
static struct <u><span style='color:blue'>hd_struct</span></u> {</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>58</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
long start_sect;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>分区在硬盘中的起始物理（绝对）扇区。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>59</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
long nr_sects;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>分区中扇区总数。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>60</span></u> } <u><span
style='color:blue'>hd</span></u>[5*<u><span style='color:blue'>MAX_HD</span></u>]={{0,0},};</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>61</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>硬盘每个分区数据块总数数组。 </p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>62</span></u>
static int <u><span style='color:blue'>hd_sizes</span></u>[5*<u><span
style='color:blue'>MAX_HD</span></u>] = {0, };</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>63</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>读端口嵌入汇编宏。读端口<span
lang=EN-US>port</span>，共读<span lang=EN-US>nr</span>字，保存在<span lang=EN-US>buf</span>中。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>64</span></u>
#define <u><span style='color:blue'>port_read</span></u>(port,<u><span
style='color:blue'>buf</span></u>,nr) \</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>65</span></u>
__asm__(<i>&quot;cld;rep;insw&quot;</i>::<i>&quot;d&quot;</i> (port),<i>&quot;D&quot;</i>
(<u><span style='color:blue'>buf</span></u>),<i>&quot;c&quot;</i> (nr):<i>&quot;cx&quot;</i>,<i>&quot;di&quot;</i>)</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>66</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>写端口嵌入汇编宏。写端口<span
lang=EN-US>port</span>，共写<span lang=EN-US>nr</span>字，从<span lang=EN-US>buf</span>中取数据。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>67</span></u>
#define <u><span style='color:blue'>port_write</span></u>(port,<u><span
style='color:blue'>buf</span></u>,nr) \</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>68</span></u>
__asm__(<i>&quot;cld;rep;outsw&quot;</i>::<i>&quot;d&quot;</i> (port),<i>&quot;S&quot;</i>
(<u><span style='color:blue'>buf</span></u>),<i>&quot;c&quot;</i> (nr):<i>&quot;cx&quot;</i>,<i>&quot;si&quot;</i>)</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>69</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>70</span></u>
extern void <u><span style='color:blue'>hd_interrupt</span></u>(void);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>硬盘中断过程（<span lang=EN-US>sys_call.s</span>，<span lang=EN-US>235</span>行）。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>71</span></u>
extern void <u><span style='color:blue'>rd_load</span></u>(void);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// </span>虚拟盘创建加载函数（<span lang=EN-US>ramdisk.c</span>，<span
lang=EN-US>71</span>行）。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>72</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>73</span></u> <b><i>/*
This may be used only once, enforced by 'static int callable' */</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; /* </span>下面该函数只在初始化时被调用一次。用静态变量<span
lang=EN-US>callable</span>作为可调用标志。<span lang=EN-US>*/</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>系统设置函数。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>函数参数<span lang=EN-US>BIOS</span>是由初始化程序<span
lang=EN-US>init/main.c</span>中<span lang=EN-US>init</span>子程序设置为指向硬盘参数表结构的指针。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>该硬盘参数表结构包含<span
lang=EN-US>2</span>个硬盘参数表的内容（共<span lang=EN-US>32</span>字节），是从内存<span
lang=EN-US>0x90080</span>处复制而来。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // 0x90080</span>处的硬盘参数表是由<span
lang=EN-US>setup.s</span>程序利用<span lang=EN-US>ROM BIOS</span>功能取得。硬盘参数表信息参见程序</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>列表后的说明。 本函数主要功能是读取<span
lang=EN-US> CMOS</span>和硬盘参数表信息，用于设置硬盘分区结构<span lang=EN-US>hd</span>，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>并尝试加载<span lang=EN-US>RAM</span>虚拟盘和根文件系统。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>74</span></u> int
<u><span style='color:blue'>sys_setup</span></u>(void * BIOS)</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>75</span></u> {</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>76</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
static int callable = 1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>限制本函数只能被调用<span lang=EN-US>1</span>次的标志。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>77</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
int i,drive;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>78</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
unsigned char cmos_disks;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>79</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
struct <u><span style='color:blue'>partition</span></u> *p;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>80</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
struct <u><span style='color:blue'>buffer_head</span></u> * bh;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>81</span></u> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>首先设置<span lang=EN-US>callable</span>标志，使得本函数只能被调用<span
lang=EN-US>1</span>次。然后设置硬盘信息数组<span lang=EN-US>hd_info[]</span>。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>如果在<span lang=EN-US>
include/linux/config.h </span>文件中已定义了符号常数<span lang=EN-US>HD_TYPE</span>，那么<span
lang=EN-US> hd_info[]</span>数组</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>已经在前面第<span
lang=EN-US>49</span>行上设置好了。否则就需要读取<span lang=EN-US>boot/setup.s</span>程序存放在内存<span
lang=EN-US>0x90080</span>处</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>开始的硬盘参数表。<span
lang=EN-US>setup.s</span>程序在内存此处连续存放着一到两个硬盘参数表。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>82</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (!callable)</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>83</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return -1;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>84</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
callable = 0;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>85</span></u>
#ifndef HD_TYPE&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>如果没有定义<span lang=EN-US>HD_TYPE</span>，则读取。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>86</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
for (drive=0 ; drive&lt;2 ; drive++) {</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>87</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>hd_info</span></u>[drive].cyl = *(unsigned short *)
BIOS;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // </span>柱面数。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>88</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>hd_info</span></u>[drive].<u><span
style='color:blue'>head</span></u> = *(unsigned char *) (2+BIOS);&nbsp; // </span>磁头数。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>89</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>hd_info</span></u>[drive].wpcom = *(unsigned short
*) (5+BIOS); // </span>写前预补偿柱面号。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>90</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>hd_info</span></u>[drive].ctl = *(unsigned char *)
(8+BIOS);&nbsp;&nbsp;&nbsp; // </span>控制字节。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>91</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>hd_info</span></u>[drive].lzone = *(unsigned short
*) (12+BIOS);// </span>磁头着陆区柱面号。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>92</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>hd_info</span></u>[drive].sect = *(unsigned char *)
(14+BIOS);&nbsp; // </span>每磁道扇区数。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>93</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
BIOS += 16;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>每个硬盘参数表长<span lang=EN-US>16</span>字节，这里<span lang=EN-US>BIOS</span>指向下一表。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>94</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // setup.s</span>程序在取<span
lang=EN-US>BIOS</span>硬盘参数表信息时，如果系统中只有<span lang=EN-US>1</span>个硬盘，就会将对应第<span
lang=EN-US>2</span>个</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>硬盘的<span lang=EN-US>16</span>字节全部清零。因此这里只要判断第<span
lang=EN-US>2</span>个硬盘柱面数是否为<span lang=EN-US>0</span>就可以知道是否有</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>第<span lang=EN-US>2</span>个硬盘了。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>95</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (<u><span style='color:blue'>hd_info</span></u>[1].cyl)</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>96</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>NR_HD</span></u>=2;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>硬盘数置为<span lang=EN-US>2</span>。</p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>97</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
else</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>98</span></u>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>NR_HD</span></u>=1;</span></p>

<p class=a><span lang=EN-US>&nbsp;<u><span style='color:blue'>99</span></u>
#endif</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>到这里，硬盘信息数组<span
lang=EN-US>hd_info[]</span>已经设置好，并且确定了系统含有的硬盘数<span lang=EN-US>NR_HD</span>。现在</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>开始设置硬盘分区结构数组<span
lang=EN-US>hd[]</span>。该数组的项<span lang=EN-US>0</span>和项<span lang=EN-US>5 </span>分别表示两个硬盘的整体参数，而</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>项<span lang=EN-US>1—4</span>和<span
lang=EN-US>6—9</span>分别表示两个硬盘的<span lang=EN-US>4</span>个分区的参数。 因此这里仅设置表示硬盘整体信息</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>的两项（项<span lang=EN-US>0</span>和<span
lang=EN-US>5</span>）。</p>

<p class=a><u><span lang=EN-US style='color:blue'>100</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i=0 ; i&lt;<u><span
style='color:blue'>NR_HD</span></u> ; i++) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>101</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>hd</span></u>[i*5].start_sect = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>硬盘起始扇区号。</p>

<p class=a><u><span lang=EN-US style='color:blue'>102</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>hd</span></u>[i*5].nr_sects = <u><span
style='color:blue'>hd_info</span></u>[i].<u><span style='color:blue'>head</span></u>*</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>103</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>hd_info</span></u>[i].sect*<u><span
style='color:blue'>hd_info</span></u>[i].cyl;&nbsp; // </span>硬盘总扇区数。</p>

<p class=a><u><span lang=EN-US style='color:blue'>104</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>105</span></u><span
lang=EN-US> </span></p>

<p class=a><u><span lang=EN-US style='color:blue'>106</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <b><i>/*</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>107</span></u><span
lang=EN-US> <b><i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;We
querry CMOS about hard disks : it could be that </i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>108</span></u><span
lang=EN-US> <b><i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;we
have a SCSI/ESDI/etc controller that is BIOS</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>109</span></u><span
lang=EN-US> <b><i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;compatable
with ST-506, and thus showing up in our</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>110</span></u><span
lang=EN-US> <b><i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BIOS
table, but not register compatable, and therefore</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>111</span></u><span
lang=EN-US> <b><i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;not
present in CMOS.</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>112</span></u><span
lang=EN-US> </span></p>

<p class=a><u><span lang=EN-US style='color:blue'>113</span></u><span
lang=EN-US> <b><i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Furthurmore,
we will assume that our ST-506 drives</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>114</span></u><span
lang=EN-US> <b><i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&lt;if
any&gt; are the primary drives in the system, and </i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>115</span></u><span
lang=EN-US> <b><i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;the
ones reflected as drive 1 or 2.</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>116</span></u><span
lang=EN-US> </span></p>

<p class=a><u><span lang=EN-US style='color:blue'>117</span></u><span
lang=EN-US> <b><i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;The
first drive is stored in the high nibble of CMOS</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>118</span></u><span
lang=EN-US> <b><i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;byte
0x12, the second in the low nibble.&nbsp; This will be</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>119</span></u><span
lang=EN-US> <b><i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;either
a 4 bit drive type or 0xf indicating use byte 0x19 </i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>120</span></u><span
lang=EN-US> <b><i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;for
an 8 bit type, drive 1, 0x1a for drive 2 in CMOS.</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>121</span></u><span
lang=EN-US> </span></p>

<p class=a><u><span lang=EN-US style='color:blue'>122</span></u><span
lang=EN-US> <b><i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Needless
to say, a non-zero value means we have </i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>123</span></u><span
lang=EN-US> <b><i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;an
AT controller hard disk for that drive.</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>124</span></u><span
lang=EN-US> </span></p>

<p class=a><u><span lang=EN-US style='color:blue'>125</span></u><span
lang=EN-US> <b><i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>126</span></u><span
lang=EN-US> <b><i>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*/</i></b></span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
/*</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span>我们对<span lang=EN-US>CMOS</span>有关硬盘的信息有些怀疑：可能会出现这样的情况，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span>我们有一块<span lang=EN-US>SCSI/ESDI/</span>等的控制器，它是以<span lang=EN-US>ST-506</span>方式与<span
lang=EN-US>BIOS</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span>相兼容的，因而会出现在我们的<span lang=EN-US>BIOS</span>参数表中，但却又不是寄存</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span>器兼容的，因此这些参数在<span lang=EN-US>CMOS</span>中又不存在。</p>

<p class=a><span lang=EN-US>&nbsp;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span>另外，我们假设<span lang=EN-US>ST-506</span>驱动器（如果有的话）是系统中的基本驱</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span>动器，也即以驱动器<span lang=EN-US>1</span>或<span lang=EN-US>2</span>出现的驱动器。</p>

<p class=a><span lang=EN-US>&nbsp;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span>第<span lang=EN-US>1</span>个驱动器参数存放在<span lang=EN-US>CMOS</span>字节<span
lang=EN-US>0x12</span>的高半字节中，第<span lang=EN-US>2</span>个</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span>存放在低半字节中。该<span lang=EN-US>4</span>位字节信息可以是驱动器类型，也可能</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span>仅是<span lang=EN-US>0xf</span>。<span lang=EN-US>0xf</span>表示使用<span
lang=EN-US>CMOS</span>中<span lang=EN-US>0x19</span>字节作为驱动器<span lang=EN-US>1</span>的<span
lang=EN-US>8</span>位</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span>类型字节，使用<span lang=EN-US>CMOS</span>中<span lang=EN-US>0x1A</span>字节作为驱动器<span
lang=EN-US>2</span>的类型字节。</p>

<p class=a><span lang=EN-US>&nbsp;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
</span>总之，一个非零值意味着硬盘是一个<span lang=EN-US>AT</span>控制器兼容硬盘。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
*/</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>127</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>这里根据上述原理，下面代码用来检测硬盘到底是不是<span
lang=EN-US>AT</span>控制器兼容的。有关<span lang=EN-US>CMOS</span>信息</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>请参见第<span lang=EN-US>4</span>章中<span lang=EN-US>4.2.3</span><span lang=EN-US>.1</span>节。这里从<span lang=EN-US>CMOS</span>偏移地址<span
lang=EN-US>0x12</span>处读出硬盘类型字节。如果低半</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>字节值（存放着第<span
lang=EN-US>2</span>个硬盘类型值）不为<span lang=EN-US>0</span>，则表示系统有两硬盘，否则表示系统只有<span
lang=EN-US>1</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>个硬盘。如果<span
lang=EN-US>0x12</span>处读出的值为<span lang=EN-US>0</span>，则表示系统中没有<span lang=EN-US>AT</span>兼容硬盘。</p>

<p class=a><u><span lang=EN-US style='color:blue'>128</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ((cmos_disks = <u><span
style='color:blue'>CMOS_READ</span></u>(0x12)) &amp; 0xf0)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>129</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (cmos_disks &amp; 0x0f)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>130</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>NR_HD</span></u> = 2;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>131</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
else</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>132</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>NR_HD</span></u> = 1;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>133</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>134</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>NR_HD</span></u> = 0;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>若<span lang=EN-US>NR_HD
= 0</span>，则两个硬盘都不是<span lang=EN-US>AT</span>控制器兼容的，两个硬盘数据结构全清零。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>若<span lang=EN-US>NR_HD
= 1</span>，则将第<span lang=EN-US>2</span>个硬盘的参数清零。</p>

<p class=a><u><span lang=EN-US style='color:blue'>135</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i = <u><span
style='color:blue'>NR_HD</span></u> ; i &lt; 2 ; i++) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>136</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>hd</span></u>[i*5].start_sect = 0;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>137</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>hd</span></u>[i*5].nr_sects = 0;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>138</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>好，到此为止我们已经真正确定了系统中所含的硬盘个数<span
lang=EN-US>NR_HD</span>。现在我们来读取每个硬盘</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>上第<span lang=EN-US>1</span>个扇区中的分区表信息，用来设置分区结构数组<span
lang=EN-US>hd[] </span>中硬盘各分区的信息。首先利</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>用读块函数<span lang=EN-US>bread()</span>读硬盘第<span
lang=EN-US>1</span>个数据块（<span lang=EN-US>fs/buffer.c</span>，第<span lang=EN-US>267</span>行），第<span
lang=EN-US>1</span>个参数（<span lang=EN-US>0x300</span>、</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // 0x305 </span>）分别是两个硬盘的设备号，第<span
lang=EN-US>2</span>个参数（<span lang=EN-US>0</span>）是所需读取的块号。若读操作成功，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>则数据会被存放在缓冲块<span
lang=EN-US>bh</span>的数据区中。若缓冲块头指针<span lang=EN-US>bh</span>为<span lang=EN-US>0</span>，则说明读操作失败，则</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>显示出错信息并停机。否则我们根据硬盘第<span
lang=EN-US>1</span>个扇区最后两个字节应该是<span lang=EN-US>0xAA55</span>来判断扇</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>区中数据的有效性，从而可以知道扇区中位于偏移<span
lang=EN-US>0x1BE</span>开始处的分区表是否有效。若有效</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>则将硬盘分区表信息放入硬盘分区结构数组<span
lang=EN-US>hd[]</span>中。最后释放<span lang=EN-US>bh</span>缓冲区。</p>

<p class=a><u><span lang=EN-US style='color:blue'>139</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (drive=0 ;
drive&lt;<u><span style='color:blue'>NR_HD</span></u> ; drive++) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>140</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (!(bh = <u><span style='color:blue'>bread</span></u>(0x300 + drive*5,0))) {&nbsp;
// 0x300</span>、<span lang=EN-US>0x305</span>是设备号。</p>

<p class=a><u><span lang=EN-US style='color:blue'>141</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>printk</span></u>(<i>&quot;Unable to read partition
table of drive %d\n\r&quot;</i>,</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>142</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;drive);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>143</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>panic</span></u>(<i>&quot;&quot;</i>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>144</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>145</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (bh-&gt;b_data[510] != 0x55 || (unsigned char)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>146</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
bh-&gt;b_data[511] != 0xAA) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>判断硬盘标志<span lang=EN-US>0xAA55</span>。</p>

<p class=a><u><span lang=EN-US style='color:blue'>147</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;<u><span style='color:blue'>printk</span></u>(<i>&quot;Bad
partition table on drive %d\n\r&quot;</i>,drive);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>148</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>panic</span></u>(<i>&quot;&quot;</i>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>149</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>150</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
p = 0x1BE + (void *)bh-&gt;b_data;&nbsp;&nbsp;&nbsp; // </span>分区表位于第<span
lang=EN-US>1</span>扇区<span lang=EN-US>0x1BE</span>处。</p>

<p class=a><u><span lang=EN-US style='color:blue'>151</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
for (i=1;i&lt;5;i++,p++) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>152</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>hd</span></u>[i+5*drive].start_sect =
p-&gt;start_sect;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>153</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>hd</span></u>[i+5*drive].nr_sects = p-&gt;nr_sects;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>154</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>155</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>brelse</span></u>(bh);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>释放为存放硬盘数据块而申请的缓冲区。</p>

<p class=a><u><span lang=EN-US style='color:blue'>156</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>现在再对每个分区中的数据块总数进行统计，并保存在硬盘分区总数据块数组<span
lang=EN-US>hd_sizes[]</span>中。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>然后让设备数据块总数指针数组的本设备项指向该数组。</p>

<p class=a><u><span lang=EN-US style='color:blue'>157</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i=0 ; i&lt;5*<u><span
style='color:blue'>MAX_HD</span></u> ; i++)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>158</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>hd_sizes</span></u>[i] = <u><span style='color:
blue'>hd</span></u>[i].nr_sects&gt;&gt;1 ;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>159</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>blk_size</span></u>[<u><span style='color:blue'>MAJOR_NR</span></u>]
= <u><span style='color:blue'>hd_sizes</span></u>;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>现在总算完成设置硬盘分区结构数组<span
lang=EN-US>hd[]</span>的任务。如果确实有硬盘存在并且已读入其分区</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>表，则显示“分区表正常”信息。然后尝试在系统内存虚拟盘中加载启动盘中包含的根文</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>件系统映像（<span
lang=EN-US>blk_drv/ramdisk.c</span>，第<span lang=EN-US>71</span>行）。即在系统设置有虚拟盘的情况下判断启动盘</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>上是否还含有根文件系统的映像数据。如果有（此时该启动盘称为集成盘）则尝试把该映像</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>加载并存放到虚拟盘中，然后把此时的根文件系统设备号<span
lang=EN-US>ROOT_DEV</span>修改成虚拟盘的设备号。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>接着再对交换设备进行初始化。最后安装根文件系统。</p>

<p class=a><u><span lang=EN-US style='color:blue'>160</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (<u><span
style='color:blue'>NR_HD</span></u>)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>161</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>printk</span></u>(<i>&quot;Partition table%s
ok.\n\r&quot;</i>,(<u><span style='color:blue'>NR_HD</span></u>&gt;1)?<i>&quot;s&quot;</i>:<i>&quot;&quot;</i>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>162</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>rd_load</span></u>();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// blk_drv/ramdisk.c</span>，第<span lang=EN-US>71</span>行。</p>

<p class=a><u><span lang=EN-US style='color:blue'>163</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>init_swapping</span></u>();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// mm/swap.c</span>，第<span lang=EN-US>199</span>行。</p>

<p class=a><u><span lang=EN-US style='color:blue'>164</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>mount_root</span></u>();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// fs/super.c</span>，第<span lang=EN-US>241</span>行。</p>

<p class=a><u><span lang=EN-US style='color:blue'>165</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (0);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>166</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>167</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>判断并循环等待硬盘控制器就绪。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>读硬盘控制器状态寄存器端口<span
lang=EN-US>HD_STATUS(0x1f7)</span>，循环检测其中的驱动器就绪比特位（位<span
lang=EN-US>6</span>）</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>是否被置位并且控制器忙位（位<span
lang=EN-US>7</span>）是否被复位。 如果返回值<span lang=EN-US>retries</span>为<span
lang=EN-US>0</span>，则表示等待控制</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>器空闲的时间已经超时而发生错误，若返回值不为<span
lang=EN-US>0</span>则说明在等待（循环）时间期限内控制器</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>回到空闲状态，<span
lang=EN-US>OK</span>！</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>实际上，我们仅需检测状态寄存器忙位（位<span
lang=EN-US>7</span>）是否为<span lang=EN-US>1</span>来判断控制器是否处于忙状态，驱动</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>器是否就绪（即位<span
lang=EN-US>6</span>是否为<span lang=EN-US>1</span>）与控制器的状态无关。因此我们可以把第<span
lang=EN-US>172</span>行语句改写成：</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>“<span lang=EN-US>while
(--retries &amp;&amp; (inb_p(HD_STATUS)&amp;0x80));</span>”另外，由于现在的<span
lang=EN-US>PC</span>机速度都很快，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>因此我们可以把等待的循环次数再加大一些，例如再增加<span
lang=EN-US>10</span>倍！</p>

<p class=a><u><span lang=EN-US style='color:blue'>168</span></u><span
lang=EN-US> static int <u><span style='color:blue'>controller_ready</span></u>(void)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>169</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>170</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int retries =
100000;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>171</span></u><span
lang=EN-US> </span></p>

<p class=a><u><span lang=EN-US style='color:blue'>172</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while (--retries
&amp;&amp; (<u><span style='color:blue'>inb_p</span></u>(<u><span
style='color:blue'>HD_STATUS</span></u>)&amp;0xc0)!=0x40);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>173</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (retries);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>返回等待循环次数。</p>

<p class=a><u><span lang=EN-US style='color:blue'>174</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>175</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>检测硬盘执行命令后的状态。（<span
lang=EN-US>win </span>表示温切斯特硬盘的缩写）</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>读取状态寄存器中的命令执行结果状态。 返回<span
lang=EN-US>0</span>表示正常；<span lang=EN-US>1</span>表示出错。如果执行命令错，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>则需要再读错误寄存器<span
lang=EN-US>HD_ERROR</span>（<span lang=EN-US>0x1f1</span>）。</p>

<p class=a><u><span lang=EN-US style='color:blue'>176</span></u><span
lang=EN-US> static int <u><span style='color:blue'>win_result</span></u>(void)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>177</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>178</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i=<u><span
style='color:blue'>inb_p</span></u>(<u><span style='color:blue'>HD_STATUS</span></u>);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>取状态信息。</p>

<p class=a><u><span lang=EN-US style='color:blue'>179</span></u><span
lang=EN-US> </span></p>

<p class=a><u><span lang=EN-US style='color:blue'>180</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ((i &amp; (<u><span
style='color:blue'>BUSY_STAT</span></u> | <u><span style='color:blue'>READY_STAT</span></u>
| <u><span style='color:blue'>WRERR_STAT</span></u> | <u><span
style='color:blue'>SEEK_STAT</span></u> | <u><span style='color:blue'>ERR_STAT</span></u>))</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>181</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
== (<u><span style='color:blue'>READY_STAT</span></u> | <u><span
style='color:blue'>SEEK_STAT</span></u>))</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>182</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return(0); <b><i>/* ok */</i></b></span></p>

<p class=a><u><span lang=EN-US style='color:blue'>183</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (i&amp;1) i=<u><span
style='color:blue'>inb</span></u>(<u><span style='color:blue'>HD_ERROR</span></u>);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>若<span lang=EN-US>ERR_STAT</span>置位，则读取错误寄存器。</p>

<p class=a><u><span lang=EN-US style='color:blue'>184</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (1);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>185</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>186</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>向硬盘控制器发送命令块。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>参数：<span lang=EN-US>drive
- </span>硬盘号<span lang=EN-US>(0-1)</span>；<span lang=EN-US>nsect - </span>读写扇区数；<span
lang=EN-US>sect&nbsp; - </span>起始扇区；</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;
//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; head&nbsp; - </span>磁头号；<span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp; cyl&nbsp;&nbsp; - </span>柱面号；<span
lang=EN-US>&nbsp;&nbsp;&nbsp; cmd&nbsp;&nbsp; - </span>命令码（见控制器命令列表）；</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp;
//&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; intr_addr() - </span>硬盘中断处理程序中将调用的<span
lang=EN-US>C</span>处理函数指针。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>该函数在硬盘控制器就绪之后，先设置全局指针变量<span
lang=EN-US>do_hd</span>为硬盘中断处理程序中将调用的</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // C</span>处理函数指针。然后再发送硬盘控制字节和<span
lang=EN-US>7</span>字节的参数命令块。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>该函数在硬盘控制器就绪之后，先设置全局函数指针变量<span
lang=EN-US>do_hd</span>指向硬盘中断处理程序中将会</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>调用的<span lang=EN-US>C</span>处理函数，然后再发送硬盘控制字节和<span
lang=EN-US>7</span>字节的参数命令块。硬盘中断处理程序的代</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>码位于<span lang=EN-US>kernel/sys_call.s</span>程序第<span
lang=EN-US>235</span>行处。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>第<span lang=EN-US>191</span>行定义<span
lang=EN-US>1</span>个寄存器变量<span lang=EN-US>__res</span>。该变量将被保存在<span
lang=EN-US>1</span>个寄存器中，以便于快速访问。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>如果想指定寄存器（如<span
lang=EN-US>eax</span>），则我们可以把该句写成“<span lang=EN-US>register char __res asm(&quot;ax&quot;);</span>”。</p>

<p class=a><u><span lang=EN-US style='color:blue'>187</span></u><span
lang=EN-US> static void <u><span style='color:blue'>hd_out</span></u>(unsigned
int drive,unsigned int nsect,unsigned int sect,</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>188</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
unsigned int <u><span style='color:blue'>head</span></u>,unsigned int
cyl,unsigned int cmd,</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>189</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
void (*intr_addr)(void))</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>190</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>191</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; register int port
asm(<i>&quot;dx&quot;</i>);&nbsp;&nbsp;&nbsp; // </span>定义局部寄存器变量并放在指定寄存器<span
lang=EN-US>dx</span>中。</p>

<p class=a><u><span lang=EN-US style='color:blue'>192</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>首先对参数进行有效性检查。如果驱动器号大于<span
lang=EN-US>1</span>（只能是<span lang=EN-US>0</span>、<span lang=EN-US>1</span>）或者磁头号大于<span
lang=EN-US>15</span>，则程</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>序不支持，停机。否则就判断并循环等待驱动器就绪。如果等待一段时间后仍未就绪则表示</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>硬盘控制器出错，也停机。</p>

<p class=a><u><span lang=EN-US style='color:blue'>193</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (drive&gt;1 || <u><span
style='color:blue'>head</span></u>&gt;15)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>194</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>panic</span></u>(<i>&quot;Trying to write bad
sector&quot;</i>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>195</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!<u><span
style='color:blue'>controller_ready</span></u>())</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>196</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>panic</span></u>(<i>&quot;HD controller not
ready&quot;</i>);</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>接着我们设置硬盘中断发生时将调用的<span
lang=EN-US>C</span>函数指针<span lang=EN-US>do_hd</span>（该函数指针定义在<span lang=EN-US>blk.h</span>文件的</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>第<span lang=EN-US>56--109</span>行之间，请特别留意其中的第<span
lang=EN-US>83</span>行和<span lang=EN-US>100</span>行）。然后在向硬盘控制器发送参数</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>和命令之前，规定要先向控制器命令端口（<span
lang=EN-US>0x3f6</span>）发送一指定硬盘的控制字节，以建立相</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>应的硬盘控制方式。该控制字节即是硬盘信息结构数组中的<span
lang=EN-US> ctl </span>字段。然后向控制器端口</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // 0x1f1–0x1f7</span>发送<span
lang=EN-US>7</span>字节的参数命令块。</p>

<p class=a><u><span lang=EN-US style='color:blue'>197</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>SET_INTR</span></u>(intr_addr);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// do_hd = intr_addr</span>在中断中被调用。</p>

<p class=a><u><span lang=EN-US style='color:blue'>198</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>outb_p</span></u>(<u><span style='color:blue'>hd_info</span></u>[drive].ctl,<u><span
style='color:blue'>HD_CMD</span></u>);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // </span>向控制寄存器输出控制字节。</p>

<p class=a><u><span lang=EN-US style='color:blue'>199</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; port=<u><span
style='color:blue'>HD_DATA</span></u>;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>置<span lang=EN-US>dx</span>为数据寄存器端口<span lang=EN-US>(0x1f0)</span>。</p>

<p class=a><u><span lang=EN-US style='color:blue'>200</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>outb_p</span></u>(<u><span style='color:blue'>hd_info</span></u>[drive].wpcom&gt;&gt;2,++port);
// </span>参数：写预补偿柱面号<span lang=EN-US>(</span>需除<span lang=EN-US>4)</span>。</p>

<p class=a><u><span lang=EN-US style='color:blue'>201</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>outb_p</span></u>(nsect,++port);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>参数：读<span lang=EN-US>/</span>写扇区总数。</p>

<p class=a><u><span lang=EN-US style='color:blue'>202</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>outb_p</span></u>(sect,++port);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>参数：起始扇区。</p>

<p class=a><u><span lang=EN-US style='color:blue'>203</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>outb_p</span></u>(cyl,++port);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>参数：柱面号低<span lang=EN-US>8</span>位。</p>

<p class=a><u><span lang=EN-US style='color:blue'>204</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>outb_p</span></u>(cyl&gt;&gt;8,++port);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>参数：柱面号高<span lang=EN-US>8</span>位。</p>

<p class=a><u><span lang=EN-US style='color:blue'>205</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>outb_p</span></u>(0xA0|(drive&lt;&lt;4)|<u><span
style='color:blue'>head</span></u>,++port);&nbsp;&nbsp;&nbsp; // </span>参数：驱动器号<span
lang=EN-US>+</span>磁头号。</p>

<p class=a><u><span lang=EN-US style='color:blue'>206</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>outb</span></u>(cmd,++port);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>命令：硬盘控制命令。</p>

<p class=a><u><span lang=EN-US style='color:blue'>207</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>208</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>等待硬盘就绪。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>该函数循环等待主状态控制器忙标志位复位。若仅有就绪或寻道结束标志置位，则表示硬盘</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>就绪，成功返回<span
lang=EN-US>0</span>。若经过一段时间仍为忙，则返回<span lang=EN-US>1</span>。</p>

<p class=a><u><span lang=EN-US style='color:blue'>209</span></u><span
lang=EN-US> static int <u><span style='color:blue'>drive_busy</span></u>(void)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>210</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>211</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned int i;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>212</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned char c;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>213</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>循环读取控制器的主状态寄存器<span
lang=EN-US>HD_STATUS</span>，等待就绪标志位置位并且忙位复位。然后检测</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>其中忙位、就绪位和寻道结束位。若仅有就绪或寻道结束标志置位，则表示硬盘就绪，返回</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // 0</span>。否则表示等待超时。于是警告显示信息。并返回<span
lang=EN-US>1</span>。</p>

<p class=a><u><span lang=EN-US style='color:blue'>214</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for (i = 0; i &lt;
50000; i++) {</span></p>

<p class=a><u><span
 lang=EN-US style='color:blue'>215</span></u><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
 c</span><span lang=EN-US> = <u><span style='color:blue'>inb_p</span></u>(<u><span
style='color:blue'>HD_STATUS</span></u>);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>取主控制器状态字节。</p>

<p class=a><u><span
 lang=EN-US style='color:blue'>216</span></u><span lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
 c</span><span lang=EN-US> &amp;= (<u><span style='color:blue'>BUSY_STAT</span></u>
| <u><span style='color:blue'>READY_STAT</span></u> | <u><span
style='color:blue'>SEEK_STAT</span></u>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>217</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (c == (<u><span style='color:blue'>READY_STAT</span></u> | <u><span
style='color:blue'>SEEK_STAT</span></u>))</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>218</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return 0;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>219</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>220</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>printk</span></u>(<i>&quot;HD controller times out\n\r&quot;</i>);&nbsp;
&nbsp;// </span>等待超时，显示信息。并返回<span lang=EN-US>1</span>。</p>

<p class=a><u><span lang=EN-US style='color:blue'>221</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return(1);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>222</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>223</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>诊断复位（重新校正）硬盘控制器。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>首先向控制寄存器端口（<span
lang=EN-US>0x3f6</span>）发送允许复位（<span
lang=EN-US>4</span>）控制字节。然后循环空操作等待一段时</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>间让控制器执行复位操作。接着再向该端口发送正常的控制字节<span
lang=EN-US>(</span>不禁止重试、重读<span lang=EN-US>)</span>，并等</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>待硬盘就绪。若等待硬盘就绪超时，则显示警告信息。然后读取错误寄存器内容，若其不等</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>于<span lang=EN-US>1</span>（表示无错误）则显示硬盘控制器复位失败信息。</p>

<p class=a><u><span lang=EN-US style='color:blue'>224</span></u><span
lang=EN-US> static void <u><span style='color:blue'>reset_controller</span></u>(void)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>225</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>226</span></u><span
lang=EN-US>&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;int&nbsp;&nbsp;&nbsp;&nbsp;
i;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>227</span></u><span
lang=EN-US> </span></p>

<p class=a><u><span lang=EN-US style='color:blue'>228</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>outb</span></u>(4,<u><span style='color:blue'>HD_CMD</span></u>);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>向控制寄存器端口发送复位控制字节。</p>

<p class=a><u><span lang=EN-US style='color:blue'>229</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(i = 0; i &lt;
1000; i++) <u><span style='color:blue'>nop</span></u>();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>等待一段时间。</p>

<p class=a><u><span lang=EN-US style='color:blue'>230</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>outb</span></u>(<u><span style='color:blue'>hd_info</span></u>[0].ctl
&amp; 0x0f ,<u><span
style='color:blue'>HD_CMD</span></u>);&nbsp; // </span>发送正常控制字节<span
lang=EN-US>(</span>不禁止重试、重读<span lang=EN-US>)</span>。</p>

<p class=a><u><span lang=EN-US style='color:blue'>231</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (<u><span
style='color:blue'>drive_busy</span></u>())</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>232</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>printk</span></u>(<i>&quot;HD-controller still
busy\n\r&quot;</i>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>233</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if ((i = <u><span
style='color:blue'>inb</span></u>(<u><span style='color:blue'>HD_ERROR</span></u>))
!= 1)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>234</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>printk</span></u>(<i>&quot;HD-controller reset
failed: %02x\n\r&quot;</i>,i);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>235</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>236</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>硬盘复位操作。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>首先复位（重新校正）硬盘控制器。然后发送硬盘控制器命令“建立驱动器参数”。在本</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>命令引起的硬盘中断处理程序中又会调用本函数。此时该函数会根据执行该命令的结果判</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>断是否要进行出错处理或是继续执行请求项处理操作。</p>

<p class=a><u><span lang=EN-US style='color:blue'>237</span></u><span
lang=EN-US> static void <u><span style='color:blue'>reset_hd</span></u>(void)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>238</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>239</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static int i;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>240</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>如果复位标志<span
lang=EN-US>reset</span>是置位的，则在把复位标志清零后，执行复位硬盘控制器操作。然后</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>针对第<span lang=EN-US>i</span>个硬盘向控制器发送“建立驱动器参数”命令。当控制器执行了该命令后，又会</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>发出硬盘中断信号。此时本函数会被中断过程调用而再次执行。由于<span
lang=EN-US>reset</span>已经标志复位，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>因此会首先去执行<span
lang=EN-US>246</span>行开始的语句，判断命令执行是否正常。若还是发生错误就会调用</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // bad_rw_intr() </span>函数以统计出错次数并根据次确定是否在设置<span
lang=EN-US>reset</span>标志。如果又设置了</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // reset</span>标志则跳转到<span
lang=EN-US>repeat</span>重新执行本函数。若复位操作正常，则针对下一个硬盘发送</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>“建立驱动器参数”命令，并作上述同样处理。如果系统中<span
lang=EN-US>NR_HD</span>个硬盘都已经正常执行</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>了发送的命令，则再次<span
lang=EN-US>do_hd_request()</span>函数开始对请求项进行处理。</p>

<p class=a><u><span lang=EN-US style='color:blue'>241</span></u><span
lang=EN-US> repeat:</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>242</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (<u><span
style='color:blue'>reset</span></u>) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>243</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>reset</span></u> = 0;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>244</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
i = -1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>初始化当前硬盘号（静态变量）。</p>

<p class=a><u><span lang=EN-US style='color:blue'>245</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>reset_controller</span></u>();</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>246</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else if (<u><span
style='color:blue'>win_result</span></u>()) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>247</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>bad_rw_intr</span></u>();</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>248</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (<u><span style='color:blue'>reset</span></u>)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>249</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
goto repeat;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>250</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>251</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; i++;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>处理下一个硬盘（第<span lang=EN-US>1</span>个是<span lang=EN-US>0</span>）。</p>

<p class=a><u><span lang=EN-US style='color:blue'>252</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (i &lt; <u><span
style='color:blue'>NR_HD</span></u>) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>253</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>hd_out</span></u>(i,<u><span style='color:blue'>hd_info</span></u>[i].sect,<u><span
style='color:blue'>hd_info</span></u>[i].sect,<u><span style='color:blue'>hd_info</span></u>[i].<u><span
style='color:blue'>head</span></u>-1,</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>254</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>hd_info</span></u>[i].cyl,<u><span
style='color:blue'>WIN_SPECIFY</span></u>,&amp;<u><span style='color:blue'>reset_hd</span></u>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>255</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>256</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>do_hd_request</span></u>();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>执行请求项处理。</p>

<p class=a><u><span lang=EN-US style='color:blue'>257</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>258</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>意外硬盘中断调用函数。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>发生意外硬盘中断时，硬盘中断处理程序中调用的默认<span
lang=EN-US>C</span>处理函数。在被调用函数指针为</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // NULL</span>时调用该函数。参见（<span
lang=EN-US>kernel/sys_call.s</span>，第<span lang=EN-US>256</span>行）。该函数在显示警告信息后</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>设置复位标志<span
lang=EN-US>reset</span>，然后继续调用请求项函数<span lang=EN-US>go_hd_request()</span>并在其中执行复位处理</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>操作。</p>

<p class=a><u><span lang=EN-US style='color:blue'>259</span></u><span
lang=EN-US> void <u><span style='color:blue'>unexpected_hd_interrupt</span></u>(void)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>260</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>261</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>printk</span></u>(<i>&quot;Unexpected HD interrupt\n\r&quot;</i>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>262</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>reset</span></u> = 1;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>263</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>do_hd_request</span></u>();</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>264</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>265</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>读写硬盘失败处理调用函数。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>如果读扇区时的出错次数大于或等于<span
lang=EN-US>7</span>次时，则结束当前请求项并唤醒等待该请求的进程，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>而且对应缓冲区更新标志复位，表示数据没有更新。如果读写一扇区时的出错次数已经大于</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // 3</span>次，则要求执行复位硬盘控制器操作（设置复位标志）。</p>

<p class=a><u><span lang=EN-US style='color:blue'>266</span></u><span
lang=EN-US> static void <u><span style='color:blue'>bad_rw_intr</span></u>(void)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>267</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>268</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (++<u><span
style='color:blue'>CURRENT</span></u>-&gt;errors &gt;= <u><span
style='color:blue'>MAX_ERRORS</span></u>)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>269</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>end_request</span></u>(0);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>270</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (<u><span
style='color:blue'>CURRENT</span></u>-&gt;errors &gt; <u><span
style='color:blue'>MAX_ERRORS</span></u>/2)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>271</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>reset</span></u> = 1;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>272</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>273</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>读操作中断调用函数。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>该函数将在硬盘读命令结束时引发的硬盘中断过程中被调用。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>在读命令执行后会产生硬盘中断信号，并执行硬盘中断处理程序，此时在硬盘中断处理程序</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>中调用的<span lang=EN-US>C</span>函数指针<span
lang=EN-US>do_hd</span>已经指向<span lang=EN-US>read_intr()</span>，因此会在一次读扇区操作完成（或出错）</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>后就会执行该函数。</p>

<p class=a><u><span lang=EN-US style='color:blue'>274</span></u><span
lang=EN-US> static void <u><span style='color:blue'>read_intr</span></u>(void)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>275</span></u><span
lang=EN-US> {</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>该函数首先判断此次读命令操作是否出错。若命令结束后控制器还处于忙状态，或者命令</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>执行错误，则处理硬盘操作失败问题，接着再次请求硬盘作复位处理并执行其他请求项。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>然后返回。每次读操作出错都会对当前请求项作出错次数累计，若出错次数不到最大允许</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>出错次数的一半，则会先执行硬盘复位操作，然后再执行本次请求项处理。若出错次数已</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>经大于等于最大允许出错次数<span
lang=EN-US>MAX_ERRORS</span>（<span lang=EN-US>7</span>次），则结束本次请求项的处理而去处理队</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>列中下一个请求项。</p>

<p class=a><u><span lang=EN-US style='color:blue'>276</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (<u><span
style='color:blue'>win_result</span></u>()) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// </span>若控制器忙、读写错或命令执行错，</p>

<p class=a><u><span lang=EN-US style='color:blue'>277</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>bad_rw_intr</span></u>();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// </span>则进行读写硬盘失败处理。</p>

<p class=a><u><span lang=EN-US style='color:blue'>278</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>do_hd_request</span></u>();&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//
</span>再次请求硬盘作相应<span lang=EN-US>(</span>复位<span lang=EN-US>)</span>处理。</p>

<p class=a><u><span lang=EN-US style='color:blue'>279</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>280</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>如果读命令没有出错，则从数据寄存器端口把<span
lang=EN-US>1</span>个扇区的数据读到请求项的缓冲区中，并且</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>递减请求项所需读取的扇区数值。若递减后不等于<span
lang=EN-US> 0</span>，表示本项请求还有数据没取完，于是</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>再次置中断调用<span
lang=EN-US>C</span>函数指针<span lang=EN-US>do_hd</span>为<span lang=EN-US>read_intr()</span>并直接返回，等待硬盘在读出另<span
lang=EN-US>1</span>个扇区</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>数据后发出中断并再次调用本函数。注意：<span
lang=EN-US>281</span>行语句中的<span lang=EN-US>256</span>是指内存字，即<span lang=EN-US>512</span>字节。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>注意<span lang=EN-US>1</span>：<span
lang=EN-US>262</span>行再次置<span lang=EN-US>do_hd</span>指针指向<span lang=EN-US>read_intr()</span>是因为硬盘中断处理程序每次调用<span
lang=EN-US>do_hd</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>时都会将该函数指针置空。参见<span
lang=EN-US>sys_call.s</span>程序第<span lang=EN-US>251—253</span>行。</p>

<p class=a><u><span lang=EN-US style='color:blue'>281</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>port_read</span></u>(<u><span style='color:blue'>HD_DATA</span></u>,<u><span
style='color:blue'>CURRENT</span></u>-&gt;buffer,256);&nbsp;&nbsp;&nbsp; // </span>读数据到请求结构缓冲区。</p>

<p class=a><u><span lang=EN-US style='color:blue'>282</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>CURRENT</span></u>-&gt;errors = 0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>清出错次数。</p>

<p class=a><u><span lang=EN-US style='color:blue'>283</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>CURRENT</span></u>-&gt;buffer += 512;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>调整缓冲区指针，指向新的空区。</p>

<p class=a><u><span lang=EN-US style='color:blue'>284</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>CURRENT</span></u>-&gt;<u><span style='color:blue'>sector</span></u>++;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>起始扇区号加<span lang=EN-US>1</span>，</p>

<p class=a><u><span lang=EN-US style='color:blue'>285</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (--<u><span
style='color:blue'>CURRENT</span></u>-&gt;nr_sectors) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;// </span>如果所需读出的扇区数还没读完，则再</p>

<p class=a><u><span lang=EN-US style='color:blue'>286</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>SET_INTR</span></u>(&amp;<u><span style='color:
blue'>read_intr</span></u>);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // </span>置硬盘调用<span
lang=EN-US>C</span>函数指针为<span lang=EN-US>read_intr()</span>。</p>

<p class=a><u><span lang=EN-US style='color:blue'>287</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>288</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>执行到此，说明本次请求项的全部扇区数据已经读完，则调用<span
lang=EN-US>end_request()</span>函数去处理请</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>求项结束事宜。 最后再次调用 <span
lang=EN-US>do_hd_request()</span>，去处理其他硬盘请求项。执行其他硬盘</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>请求操作。</p>

<p class=a><u><span lang=EN-US style='color:blue'>289</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>end_request</span></u>(1);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>数据已更新标志置位（<span lang=EN-US>1</span>）。</p>

<p class=a><u><span lang=EN-US style='color:blue'>290</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>do_hd_request</span></u>();</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>291</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>292</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>写扇区中断调用函数。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>该函数将在硬盘写命令结束时引发的硬盘中断过程中被调用。函数功能与<span
lang=EN-US>read_intr()</span>类似。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>在写命令执行后会产生硬盘中断信号，并执行硬盘中断处理程序，此时在硬盘中断处理程序</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>中调用的<span lang=EN-US>C</span>函数指针<span
lang=EN-US>do_hd</span>已经指向<span lang=EN-US>write_intr()</span>，因此会在一次写扇区操作完成（或出错）</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>后就会执行该函数。</p>

<p class=a><u><span lang=EN-US style='color:blue'>293</span></u><span
lang=EN-US> static void <u><span style='color:blue'>write_intr</span></u>(void)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>294</span></u><span
lang=EN-US> {</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>该函数首先判断此次写命令操作是否出错。若命令结束后控制器还处于忙状态，或者命令</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>执行错误，则处理硬盘操作失败问题，接着再次请求硬盘作复位处理并执行其他请求项。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>然后返回。在 <span
lang=EN-US>bad_rw_intr() </span>函数中，每次操作出错都会对当前请求项作出错次数累计，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>若出错次数不到最大允许出错次数的一半，则会先执行硬盘复位操作，然后再执行本次请</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>求项处理。若出错次数已经大于等于最大允许出错次数<span
lang=EN-US>MAX_ERRORS</span>（<span lang=EN-US>7</span>次），则结束本次</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>请求项的处理而去处理队列中下一个请求项。<span
lang=EN-US>do_hd_request()</span>中会根据当时具体的标志</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>状态来判别是否需要先执行复位、重新校正等操作，然后再继续或处理下一个请求项。</p>

<p class=a><u><span lang=EN-US style='color:blue'>295</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (<u><span
style='color:blue'>win_result</span></u>()) {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;// </span>如果硬盘控制器返回错误信息，</p>

<p class=a><u><span lang=EN-US style='color:blue'>296</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>bad_rw_intr</span></u>();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;// </span>则首先进行硬盘读写失败处理，</p>

<p class=a><u><span lang=EN-US style='color:blue'>297</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>do_hd_request</span></u>();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;// </span>再次请求硬盘作相应<span lang=EN-US>(</span>复位<span
lang=EN-US>)</span>处理。</p>

<p class=a><u><span lang=EN-US style='color:blue'>298</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>299</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>此时说明本次写一扇区操作成功，因此将欲写扇区数减<span
lang=EN-US>1</span>。若其不为<span lang=EN-US>0</span>，则说明还有扇区</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>要写，于是把当前请求起始扇区号<span
lang=EN-US> +1</span>，并调整请求项数据缓冲区指针指向下一块欲写的</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>数据。然后再重置硬盘中断处理程序中调用的<span
lang=EN-US>C</span>函数指针<span lang=EN-US>do_hd</span>（指向本函数）。接着向</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>控制器数据端口写入<span
lang=EN-US>512</span>字节数据，然后函数返回去等待控制器把这些数据写入硬盘后产</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>生的中断。</p>

<p class=a><u><span lang=EN-US style='color:blue'>300</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (--<u><span
style='color:blue'>CURRENT</span></u>-&gt;nr_sectors) {&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// </span>若还有扇区要写，则</p>

<p class=a><u><span lang=EN-US style='color:blue'>301</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>CURRENT</span></u>-&gt;<u><span style='color:blue'>sector</span></u>++;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// </span>当前请求起始扇区号<span lang=EN-US>+1</span>，</p>

<p class=a><u><span lang=EN-US style='color:blue'>302</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>CURRENT</span></u>-&gt;buffer += 512;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//
</span>调整请求缓冲区指针，</p>

<p class=a><u><span lang=EN-US style='color:blue'>303</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>SET_INTR</span></u>(&amp;<u><span style='color:
blue'>write_intr</span></u>);&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// do_hd</span>置函数指针为<span
lang=EN-US>write_intr()</span>。</p>

<p class=a><u><span lang=EN-US style='color:blue'>304</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>port_write</span></u>(<u><span style='color:blue'>HD_DATA</span></u>,<u><span
style='color:blue'>CURRENT</span></u>-&gt;buffer,256);&nbsp; // </span>向数据端口写<span
lang=EN-US>256</span>字。</p>

<p class=a><u><span lang=EN-US style='color:blue'>305</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>306</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>若本次请求项的全部扇区数据已经写完，则调用<span
lang=EN-US>end_request()</span>函数去处理请求项结束事宜。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>最后再次调用 <span
lang=EN-US>do_hd_request()</span>，去处理其他硬盘请求项。执行其他硬盘请求操作。</p>

<p class=a><u><span lang=EN-US style='color:blue'>307</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>end_request</span></u>(1);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>处理请求结束事宜（已设置更新标志）。</p>

<p class=a><u><span lang=EN-US style='color:blue'>308</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>do_hd_request</span></u>();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//
</span>执行其他硬盘请求操作。</p>

<p class=a><u><span lang=EN-US style='color:blue'>309</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>310</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>硬盘重新校正（复位）中断调用函数。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>该函数会在硬盘执行重新校正操作而引发的硬盘中断中被调用。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>如果硬盘控制器返回错误信息，则函数首先进行硬盘读写失败处理，然后请求硬盘作相应</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>（复位）处理。 在 <span
lang=EN-US>bad_rw_intr() </span>函数中，每次操作出错都会对当前请求项作出错次数</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>累计，若出错次数不到最大允许出错次数的一半，则会先执行硬盘复位操作，然后再执行</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>本次请求项处理。若出错次数已经大于等于最大允许出错次数<span
lang=EN-US>MAX_ERRORS</span>（<span lang=EN-US>7</span>次），则结</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>束本次请求项的处理而去处理队列中下一个请求项。<span
lang=EN-US>do_hd_request() </span>中会根据当时具体</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>的标志状态来判别是否需要先执行复位、重新校正等操作，然后再继续或处理下一请求项。</p>

<p class=a><u><span lang=EN-US style='color:blue'>311</span></u><span
lang=EN-US> static void <u><span style='color:blue'>recal_intr</span></u>(void)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>312</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>313</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (<u><span
style='color:blue'>win_result</span></u>())&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>若返回出错，则调用<span lang=EN-US>bad_rw_intr()</span>。</p>

<p class=a><u><span lang=EN-US style='color:blue'>314</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>bad_rw_intr</span></u>();</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>315</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>do_hd_request</span></u>();</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>316</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>317</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>硬盘操作超时处理。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>本函数会在<span lang=EN-US>do_timer()</span>中（<span
lang=EN-US>kernel/sched.c</span>，第<span lang=EN-US>340</span>行）被调用。在向硬盘控制器发送了</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>一个命令后，若在经过了<span
lang=EN-US>hd_timeout</span>个系统滴答后控制器还没有发出一个硬盘中断信号，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>则说明控制器（或硬盘）操作超时。此时<span
lang=EN-US>do_timer()</span>就会调用本函数设置复位标志<span lang=EN-US>reset</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>并调用<span lang=EN-US>do_hd_request()</span>执行复位处理。若在预定时间内（<span
lang=EN-US>200</span>滴答）硬盘控制器发出了硬</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>盘中断并开始执行硬盘中断处理程序，那么<span
lang=EN-US>ht_timeout</span>值就会在中断处理程序中被置<span lang=EN-US>0</span>。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>此时<span lang=EN-US>do_timer()</span>就会跳过本函数。</p>

<p class=a><u><span lang=EN-US style='color:blue'>318</span></u><span
lang=EN-US> void <u><span style='color:blue'>hd_times_out</span></u>(void)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>319</span></u><span
lang=EN-US> {</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>如果当前并没有请求项要处理（设备请求项指针为<span
lang=EN-US>NULL</span>），则无超时可言，直接返回。否</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>则先显示警告信息，然后判断当前请求项执行过程中发生的出错次数是否已经大于设定值</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // MAX_ERRORS</span>（<span
lang=EN-US>7</span>）。如果是则以失败形式结束本次请求项的处理（不设置数据更新标志）。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>然后把中断过程中调用的<span
lang=EN-US>C</span>函数指针<span lang=EN-US>do_hd</span>置空，并设置复位标志<span lang=EN-US>reset</span>，继而在请求项</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>处理函数<span lang=EN-US>do_hd_request()</span>中去执行复位操作。</p>

<p class=a><u><span lang=EN-US style='color:blue'>320</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (!<u><span
style='color:blue'>CURRENT</span></u>)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>321</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>322</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>printk</span></u>(<i>&quot;HD timeout&quot;</i>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>323</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (++<u><span
style='color:blue'>CURRENT</span></u>-&gt;errors &gt;= <u><span
style='color:blue'>MAX_ERRORS</span></u>)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>324</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>end_request</span></u>(0);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>325</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>SET_INTR</span></u>(<u><span style='color:blue'>NULL</span></u>);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>令<span lang=EN-US>do_hd = NULL,time_out=200</span>。</p>

<p class=a><u><span lang=EN-US style='color:blue'>326</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>reset</span></u> = 1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>设置复位标志。</p>

<p class=a><u><span lang=EN-US style='color:blue'>327</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>do_hd_request</span></u>();</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>328</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>329</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; //// </span>执行硬盘读写请求操作。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>该函数根据设备当前请求项中的设备号和起始扇区号信息首先计算得到对应硬盘上的柱面号、</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>当前磁道中扇区号、磁头号数据，然后再根据请求项中的命令（<span
lang=EN-US>READ/WRITE</span>）对硬盘发送相应</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>读<span lang=EN-US>/</span>写命令。
若控制器复位标志或硬盘重新校正标志已被置位，那么首先会去执行复位或重新</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>校正操作。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>若请求项此时是块设备的第<span
lang=EN-US>1</span>个（原来设备空闲），则块设备当前请求项指针会直接指向该请</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>求项（参见<span lang=EN-US>ll_rw_blk.c</span>，<span
lang=EN-US>28</span>行），并会立刻调用本函数执行读写操作。否则在一个读写操作</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>完成而引发的硬盘中断过程中，若还有请求项需要处理，则也会在硬盘中断过程中调用本函数。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>参见<span lang=EN-US>kernel/sys_call.s</span>，<span
lang=EN-US>235</span>行。</p>

<p class=a><u><span lang=EN-US style='color:blue'>330</span></u><span
lang=EN-US> void <u><span style='color:blue'>do_hd_request</span></u>(void)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>331</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>332</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int i,r;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>333</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned int
block,dev;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>334</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned int sec,<u><span
style='color:blue'>head</span></u>,cyl;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>335</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; unsigned int nsect;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>336</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>函数首先检测请求项的合法性。若请求队列中已没有请求项则退出（参见<span
lang=EN-US>blk.h</span>，<span lang=EN-US>127</span>行）。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>然后取设备号中的子设备号（见列表后对硬盘设备号的说明）以及设备当前请求项中的起始</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>扇区号。子设备号即对应硬盘上各分区。如果子设备号不存在或者起始扇区大于该
分区扇</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>区数<span lang=EN-US>-2</span>，则结束该请求项，并跳转到标号<span
lang=EN-US>repeat</span>处（定义在<span lang=EN-US>INIT_REQUEST</span>开始处）。因为</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>一次要求读写一块数据（<span
lang=EN-US>2</span>个扇区，即<span lang=EN-US>1024</span>字节），所以请求的扇区号不能大于分区中最后</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>倒数第二个扇区号。然后通过加上子设备号对应分区的起始扇区号，就把需要读写的块对应</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>到整个硬盘的绝对扇区号<span
lang=EN-US>block</span>上。而子设备号被<span lang=EN-US>5</span>整除即可得到对应的硬盘号。</p>

<p class=a><u><span lang=EN-US style='color:blue'>337</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>INIT_REQUEST</span></u>;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>338</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dev = <u><span
style='color:blue'>MINOR</span></u>(<u><span style='color:blue'>CURRENT</span></u>-&gt;dev);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>339</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; block = <u><span
style='color:blue'>CURRENT</span></u>-&gt;<u><span style='color:blue'>sector</span></u>;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// </span>请求的起始扇区。</p>

<p class=a><u><span lang=EN-US style='color:blue'>340</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (dev &gt;= 5*<u><span
style='color:blue'>NR_HD</span></u> || block+2 &gt; <u><span style='color:blue'>hd</span></u>[dev].nr_sects)
{</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>341</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>end_request</span></u>(0);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>342</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
goto repeat;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>该标号在<span lang=EN-US>blk.h</span>最后面。</p>

<p class=a><u><span lang=EN-US style='color:blue'>343</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>344</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; block += <u><span
style='color:blue'>hd</span></u>[dev].start_sect;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>345</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dev /= 5;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>此时<span lang=EN-US>dev</span>代表硬盘号（硬盘<span lang=EN-US>0</span>还是硬盘<span
lang=EN-US>1</span>）。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>然后根据求得的绝对扇区号<span
lang=EN-US>block</span>和硬盘号<span lang=EN-US>dev</span>，我们就可以计算出对应硬盘中的磁道中扇</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>区号（<span lang=EN-US>sec</span>）、所在柱面号（<span
lang=EN-US>cyl</span>） 和磁头号（<span lang=EN-US>head</span>）。 下面嵌入的汇编代码即用来根据硬</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>盘信息结构中的每磁道扇区数和硬盘磁头数来计算这些数据。计算方法为：</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // 310--311</span>行代码初始时<span
lang=EN-US>eax</span>是扇区号<span lang=EN-US>block</span>，<span lang=EN-US>edx</span>中置<span
lang=EN-US>0</span>。<span lang=EN-US>divl</span>指令把<span lang=EN-US>edx:eax</span>组成的扇区</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>号除以每磁道扇区数（<span
lang=EN-US>hd_info[dev].sect</span>），所得整数商值在<span lang=EN-US>eax</span>中，余数在<span
lang=EN-US>edx</span>中。其</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>中<span lang=EN-US>eax</span>中是到指定位置的对应总磁道数（所有磁头面），<span
lang=EN-US>edx</span>中是当前磁道上的扇区号。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // 312--313</span>行代码初始时<span
lang=EN-US>eax</span>是计算出的对应总磁道数，<span lang=EN-US>edx</span>中置<span lang=EN-US>0</span>。<span
lang=EN-US>divl</span>指令把<span lang=EN-US>edx:eax</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>的对应总磁道数除以硬盘总磁头数（<span
lang=EN-US>hd_info[dev].head</span>），在<span lang=EN-US>eax</span>中得到的整除值是柱面</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>号（<span lang=EN-US>cyl</span>），<span
lang=EN-US>edx</span>中得到的余数就是对应得当前磁头号（<span lang=EN-US>head</span>）。</p>

<p class=a><u><span lang=EN-US style='color:blue'>346</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm__(<i>&quot;divl
%4&quot;</i>:<i>&quot;=a&quot;</i> (block),<i>&quot;=d&quot;</i> (sec):<i>&quot;0&quot;</i>
(block),<i>&quot;1&quot;</i> (0),</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>347</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<i>&quot;r&quot;</i> (<u><span style='color:blue'>hd_info</span></u>[dev].sect));</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>348</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; __asm__(<i>&quot;divl
%4&quot;</i>:<i>&quot;=a&quot;</i> (cyl),<i>&quot;=d&quot;</i> (<u><span
style='color:blue'>head</span></u>):<i>&quot;0&quot;</i> (block),<i>&quot;1&quot;</i>
(0),</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>349</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<i>&quot;r&quot;</i> (<u><span style='color:blue'>hd_info</span></u>[dev].<u><span
style='color:blue'>head</span></u>));</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>350</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sec++;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;// </span>对计算所得当前磁道扇区号进行调整。</p>

<p class=a><u><span lang=EN-US style='color:blue'>351</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nsect = <u><span
style='color:blue'>CURRENT</span></u>-&gt;nr_sectors;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;//
</span>欲读<span lang=EN-US>/</span>写的扇区数。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>此时我们得到了欲读写的硬盘起始扇区<span
lang=EN-US>block</span>所对应的硬盘上柱面号（<span lang=EN-US>cyl</span>）、在当前磁道</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>上的扇区号（<span
lang=EN-US>sec</span>）、磁头号（<span lang=EN-US>head</span>）以及欲读写的总扇区数（<span
lang=EN-US>nsect</span>）。 接着我们可以根</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>据这些信息向硬盘控制器发送<span
lang=EN-US>I/O</span>操作信息了。 但在发送之前我们还需要先看看是否有复</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>位控制器状态和重新校正硬盘的标志。通常在复位操作之后都需要重新校正硬盘磁头位置。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>若这些标志已被置位，则说明前面的硬盘操作可能出现了一些问题，或者现在是系统第一</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>次硬盘读写操作等情况。 于是我们就需要重新复位硬盘或控制器并重新校正硬盘。</p>

<p class=a><span lang=EN-US>&nbsp;</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>如果此时复位标志<span
lang=EN-US>reset</span>是置位的，则需要执行复位操作。复位硬盘和控制器，并置硬盘</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>需要重新校正标志，返回。<span
lang=EN-US>reset_hd()</span>将首先向硬盘控制器发送复位（重新校正）命令，</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>然后发送硬盘控制器命令“建立驱动器参数”。</p>

<p class=a><u><span lang=EN-US style='color:blue'>352</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (<u><span
style='color:blue'>reset</span></u>) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>353</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>recalibrate</span></u> = 1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>置需重新校正标志。</p>

<p class=a><u><span lang=EN-US style='color:blue'>354</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>reset_hd</span></u>();</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>355</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>356</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>如果此时重新校正标志（<span
lang=EN-US>recalibrate</span>）是置位的，则首先复位该标志，然后向硬盘控制</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>器发送重新校正命令。该命令会执行寻道操作，让处于任何地方的磁头移动到<span
lang=EN-US>0</span>柱面。</p>

<p class=a><u><span lang=EN-US style='color:blue'>357</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (<u><span
style='color:blue'>recalibrate</span></u>) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>358</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>recalibrate</span></u> = 0;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>359</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>hd_out</span></u>(dev,<u><span style='color:blue'>hd_info</span></u>[<u><span
style='color:blue'>CURRENT_DEV</span></u>].sect,0,0,0,</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>360</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>WIN_RESTORE</span></u>,&amp;<u><span
style='color:blue'>recal_intr</span></u>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>361</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
return;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>362</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>如果以上两个标志都没有置位，那么我们就可以开始向硬盘控制器发送真正的数据读<span
lang=EN-US>/</span>写</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>操作命令了。如果当前请求是写扇区操作，则发送写命令，循环读取状态寄存器信息并判</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>断请求服务标志<span
lang=EN-US>DRQ_STAT</span>是否置位。<span lang=EN-US>DRQ_STAT</span>是硬盘状态寄存器的请求服务位，表示驱</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>动器已经准备好在主机和数据端口之间传输一个字或一个字节的数据。这方面的信息可参</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>见程序前面的硬盘操作读<span
lang=EN-US>/</span>写时序图。如果请求服务<span lang=EN-US>DRQ</span>置位则退出循环。 若等到循环结</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>束也没有置位，则表示发送的要求写硬盘命令失败，于是跳转去处理出现的问题或继续执</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>行下一个硬盘请求。否则我们就可以向硬盘控制器数据寄存器端口<span
lang=EN-US>HD_DATA</span>写入<span lang=EN-US>1</span>个扇区</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>的数据。</p>

<p class=a><u><span lang=EN-US style='color:blue'>363</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (<u><span
style='color:blue'>CURRENT</span></u>-&gt;cmd == <u><span style='color:blue'>WRITE</span></u>)
{</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>364</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>hd_out</span></u>(dev,nsect,sec,<u><span
style='color:blue'>head</span></u>,cyl,<u><span style='color:blue'>WIN_WRITE</span></u>,&amp;<u><span
style='color:blue'>write_intr</span></u>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>365</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
for(i=0 ; i&lt;10000 &amp;&amp; !(r=<u><span style='color:blue'>inb_p</span></u>(<u><span
style='color:blue'>HD_STATUS</span></u>)&amp;<u><span style='color:blue'>DRQ_STAT</span></u>)
; i++)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>366</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<b><i>/* nothing */</i></b> ;</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>367</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
if (!r) {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>368</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>bad_rw_intr</span></u>();</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>369</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
goto repeat;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>该标号在<span lang=EN-US>blk.h</span>文件最后面。</p>

<p class=a><u><span lang=EN-US style='color:blue'>370</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
}</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>371</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>port_write</span></u>(<u><span style='color:blue'>HD_DATA</span></u>,<u><span
style='color:blue'>CURRENT</span></u>-&gt;buffer,256);</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>如果当前请求是读硬盘数据，则向硬盘控制器发送读扇区命令。若命令无效则停机。</p>

<p class=a><u><span lang=EN-US style='color:blue'>372</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else if (<u><span
style='color:blue'>CURRENT</span></u>-&gt;cmd == <u><span style='color:blue'>READ</span></u>)
{</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>373</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>hd_out</span></u>(dev,nsect,sec,<u><span
style='color:blue'>head</span></u>,cyl,<u><span style='color:blue'>WIN_READ</span></u>,&amp;<u><span
style='color:blue'>read_intr</span></u>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>374</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } else</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>375</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<u><span style='color:blue'>panic</span></u>(<i>&quot;unknown hd-command&quot;</i>);</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>376</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>377</span></u><span
lang=EN-US> </span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>硬盘系统初始化。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>设置硬盘中断描述符，并允许硬盘控制器发送中断请求信号。</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>该函数设置硬盘设备的请求项处理函数指针为<span
lang=EN-US>do_hd_request()</span>，然后设置硬盘中断门描述</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>符。<span lang=EN-US>hd_interrupt</span>（<span
lang=EN-US>kernel/sys_call.s</span>，第<span lang=EN-US>235</span>行）是其中断处理过程地址。 硬盘中断号</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>为<span lang=EN-US>int
0x2E</span>（<span lang=EN-US>46</span>），对应<span
 lang=EN-US>8259A</span>芯片的中断请求信号<span lang=EN-US>IRQ13</span>。接着复位接联的主<span
 lang=EN-US>8259A</span><span lang=EN-US> int2</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>的屏蔽位，允许从片发出中断请求信号。再复位硬盘的中断请求屏蔽位（在从片上），允许</p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>硬盘控制器发送中断请求信号。中断描述符表<span
lang=EN-US>IDT</span>内中断门描述符设置宏<span lang=EN-US>set_intr_gate()</span></p>

<p class=a><span lang=EN-US>&nbsp;&nbsp;&nbsp; // </span>在<span lang=EN-US>include/asm/system.h</span>中实现。</p>

<p class=a><u><span lang=EN-US style='color:blue'>378</span></u><span
lang=EN-US> void <u><span style='color:blue'>hd_init</span></u>(void)</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>379</span></u><span
lang=EN-US> {</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>380</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>blk_dev</span></u>[<u><span style='color:blue'>MAJOR_NR</span></u>].request_fn
= <u><span style='color:blue'>DEVICE_REQUEST</span></u>;&nbsp;&nbsp;&nbsp;&nbsp;
// do_hd_request()</span>。</p>

<p class=a><u><span lang=EN-US style='color:blue'>381</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>set_intr_gate</span></u>(0x2E,&amp;<u><span
style='color:blue'>hd_interrupt</span></u>);&nbsp; // </span>设置中断门中处理函数指针。</p>

<p class=a><u><span lang=EN-US style='color:blue'>382</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>outb_p</span></u>(<u><span style='color:blue'>inb_p</span></u>(0x21)&amp;0xfb,0x21);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>复位接联的主<span
 lang=EN-US>8259A</span><span lang=EN-US> int2</span>的屏蔽位。</p>

<p class=a><u><span lang=EN-US style='color:blue'>383</span></u><span
lang=EN-US>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <u><span
style='color:blue'>outb</span></u>(<u><span style='color:blue'>inb_p</span></u>(0xA1)&amp;0xbf,0xA1);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
// </span>复位硬盘中断请求屏蔽位（在从片上）。</p>

<p class=a><u><span lang=EN-US style='color:blue'>384</span></u><span
lang=EN-US> }</span></p>

<p class=a><u><span lang=EN-US style='color:blue'>385</span></u><span
lang=EN-US> </span></p>

<div class=a align=center style='text-align:center'><span lang=EN-US>

<hr size=4 width="100%" align=center>

</span></div>

<p class=MsoNormal><span lang=EN-US>&nbsp;</span></p>

</div>

</body>

</html>
